Generate PDFs, Word docs, Excel spreadsheets, and PowerPoint presentations from any Salesforce record. Merge PDFs, add barcodes and QR codes, compute totals — 100% native, zero external dependencies, completely free.
| Severity | Count | Status |
|---|---|---|
| Critical | 0 | ✅ |
| High | 0 | ✅ |
| Moderate | 380 | Style/complexity only |
| Low | 652 | ApexDoc, SLDS suggestions |
| Info | 56 | Whitespace, copy-paste |
Scanned with sf code-analyzer run --rule-selector "recommended" — the rule set used by Salesforce Security Review. Zero security violations.
New install:
sf package install --package 04tal000006PDOPAA4 --wait 10 --target-org <your-org>Install in Production | Install in Sandbox
Then: Assign DocGen Admin permission set | Enable Blob.toPdf() Release Update | Open the DocGen app
If you previously installed the unnamespaced "Document Generation" package:
- Uninstall the old package (Setup > Installed Packages > Document Generation > Uninstall)
- Install the new namespaced package using the links above
- Re-assign the DocGen Admin or DocGen User permission sets
- Re-create your templates (the old templates used different custom object API names without namespace)
Why the change? The package now uses the
portwoodglobalnamespace for better isolation, upgrade safety, and Salesforce Accelerator distribution. This is a one-time migration.
- Create a template — pick Word, Excel, or PowerPoint. Choose your Salesforce object.
- Select your fields — use the visual query builder to pick fields, parent lookups, and child records.
- Add tags and upload — type
{Name}where you want data. Upload the file. - Generate — from any record page, in bulk, or from a Flow.
| Tag | What It Does | Example |
|---|---|---|
{FieldName} |
Insert a field value | {Name}, {Email}, {Phone} |
{Parent.Field} |
Pull from a related record | {Account.Name}, {Owner.Email} |
{#ChildList}...{/ChildList} |
Repeat for each child record | {#Contacts}{FirstName}{/Contacts} |
{#BoolField}...{/BoolField} |
Show/hide based on field value | {#IsActive}Active member{/IsActive} |
{RichTextField} |
Rich text with formatting and images | {Description} on a Rich Text Area |
| Tag | Output | Works In |
|---|---|---|
{CloseDate:MM/dd/yyyy} |
03/18/2026 | All formats |
{Amount:currency} |
$500,000.00 | All formats |
{Rate:percent} |
15.5% | All formats |
{Quantity:number} |
1,234 | All formats |
{Price:#,##0.00} |
1,234.56 | All formats |
Place these outside the loop to compute totals from child records:
| Tag | Example |
|---|---|
{SUM:List.Field} |
{SUM:QuoteLineItems.TotalPrice} |
{COUNT:List} |
{COUNT:Contacts} |
{AVG:List.Field} |
{AVG:OpportunityLineItems.UnitPrice} |
{MIN:List.Field} / {MAX:List.Field} |
{MIN:QuoteLineItems.Quantity} |
Zero extra SOQL — computed from child data already in memory.
Rendered as CSS in PDF output. No fonts, no images, no external services.
| Tag | What You Get |
|---|---|
{*ProductCode} |
Code 128 barcode |
{*ProductCode:code128:300x80} |
Barcode at 300px wide, 80px tall |
{*Website:qr} |
QR code at 150px (default) |
{*TrackingUrl:qr:200} |
QR code at 200px square |
QR codes support up to 255 characters — enough for a full Salesforce text field or URL.
| Tag | What It Does |
|---|---|
{%Logo__c} |
Insert image at original size (from image metadata when available) |
{%Logo__c:200x60} |
Fixed size: width 200px, height 60px |
{%Logo__c:100%x} |
Fixed width: 100% of page content width, keep aspect ratio |
{%Logo__c:x50%} |
Fixed height: 50% of page content height, keep aspect ratio |
{%Logo__c:m100%x} |
Max width: shrink to fit page width, never upscale |
{%Logo__c:xm50%} |
Max height: shrink to 50% page height, never upscale |
{%Logo__c:m100%xm50%} |
Max width + max height constraints (shrink-to-fit) |
Store a ContentVersion ID (starts with 068) in a text field. Works in Word templates — PDF and DOCX output.
Image size syntax is :widthxheight with optional tokens:
300or300px= pixels100%= percentage of current page content areamprefix = max constraint (shrink only, CSS-style max behavior)- blank side is allowed:
100%x,x100%,m100%x,xm50%
Rich text fields ({Description}, {Notes__c}) render with full formatting (bold, italic, lists) in both PDF and DOCX output.
Images in rich text fields:
| Output | Rich Text Images | Notes |
|---|---|---|
| ✅ Works | Blob.toPdf() resolves Salesforce image URLs natively |
|
| DOCX | ❌ Not supported | Salesforce rtaImage servlet URLs are inaccessible server-side (CORS + redirect restrictions). Use {%FieldName} image tags instead |
Recommendation: For documents that need images in DOCX format, upload the image as a Salesforce File, store the ContentVersion ID in a text field, and use {%FieldName} image tags. This works in both PDF and DOCX.
Child loops repeat whatever content is between the opening and closing tags — including page breaks. This means you can put each child record on its own page just by adding a page break inside the loop.
Example: One receipt per Opportunity
Say you have an Account with multiple Opportunities and you want each Opportunity printed as a separate receipt page. In your Word template:
{#Opportunities}
RECEIPT
Customer: {Account.Name}
Date: {CloseDate:MM/dd/yyyy}
Amount: {Amount:currency}
Rep: {Owner.Name}
Thank you for your business!
← page break here
{/Opportunities}
Insert the page break in Word (Insert → Page Break, or Ctrl+Enter) right before the closing {/Opportunities} tag. Each Opportunity gets its own full page.
How to set it up:
- Open your
.docxtemplate in Word - Place your opening loop tag (
{#Opportunities}) at the top - Design one page of content using merge tags
- At the bottom, insert a Page Break (Insert → Page Break)
- Place the closing tag (
{/Opportunities}) right after the page break - Upload the template — each child record gets its own page
This works with any child loop — Contacts, Line Items, Cases, custom objects. Anything you can loop over, you can page-break over. Combine it with images, barcodes, QR codes, and formatting tags to build invoices, packing slips, certificates, or anything that needs one page per record.
| Format | Template | Output | Images | Barcodes/QR | Rich Text | Best For |
|---|---|---|---|---|---|---|
| Word | .docx |
PDF or DOCX | Yes | Yes (PDF) | Yes | Contracts, proposals, letters, invoices |
| Excel | .xlsx |
XLSX | No | No | No | Data exports, reports, financial summaries |
| PowerPoint | .pptx |
PPTX | No | No | No | Presentations, slide decks |
All formats support: field tags, parent lookups, child loops, aggregates, conditionals, date formatting, number/currency formatting.
Word is the most capable — it's the only format that supports images, barcodes, QR codes, rich text, and PDF output.
Five ways to combine PDFs, all running client-side in the browser:
| Mode | How It Works |
|---|---|
| Generate & Merge | Generate from a template, then append existing PDFs from the record |
| Document Packets | Select multiple templates, generate them all, merge into one PDF |
| Merge Only | Combine existing PDFs on the record with drag-and-drop ordering |
| Child Record PDFs | Pick a child relationship (e.g., Opportunities), filter, select PDFs from child records, merge |
| Bulk Merge | After bulk generation, merge all generated PDFs into one downloadable document |
Each PDF is fetched in its own Apex call (fresh 6 MB heap). The merge engine (docGenPdfMerger.js) handles the binary work — parsing object graphs, renumbering references, flattening page trees, writing cross-reference tables. No size limits on download. Save to record up to ~3 MB.
Child Record PDFs — From a parent record (e.g., Account), select a child relationship, optionally filter with a WHERE clause (e.g., StageName = 'Closed Won' AND CloseDate = THIS_MONTH), browse PDFs grouped by child record with Select All, and merge into one document.
Bulk Merge — After running bulk generation, each completed job shows a merge icon in the Recent Jobs list. Click it to download all generated PDFs merged into a single file. Name your jobs for easy searching later.
| Technique | What It Does | Impact |
|---|---|---|
| Pre-decomposition | Templates unzipped on save; generation loads only XML, never the full ZIP | ~75% heap reduction |
| Zero-heap images | PDF images referenced by URL, not loaded into memory | Unlimited images |
| Client-side assembly | Browser builds DOCX/XLSX files; each image gets its own request | No size limit |
| Client-side PDF merge | PDFs fetched one at a time, merged in browser via pure JS engine | Unlimited merge |
| Multi-level queries | One SOQL per relationship depth, stitched in Apex | 3 levels = 3 queries |
| Action | Inputs | Output |
|---|---|---|
DocGenFlowAction |
templateId, recordId | contentDocumentId |
DocGenBulkFlowAction |
templateId, queryCondition | jobId |
Both work in Record-Triggered Flows, Screen Flows, and Subflows.
Generate documents for hundreds of records at once. Enter a filter condition, click Submit. Real-time progress tracking via the Bulk Generate tab.
Drop docGenRunner onto any Lightning Record Page via App Builder. Full UI with template selection, output mode, PDF merging, and document packets.
| Limitation | Details | Workaround |
|---|---|---|
| PDF fonts | Helvetica, Times, Courier, Arial Unicode MS only | Generate as DOCX for custom fonts |
| PDF file size | ~3 MB per individual PDF for merge/save | Download has no limit |
| Barcodes/QR | PDF output only | Not available in DOCX/XLSX/PPTX |
| Images | Word templates only | Place static images directly in Excel/PPTX |
| Excel/PPTX output | Native format only, no PDF conversion | Use Word template for PDF |
| Heap (sync) | 6 MB per transaction | Use DOCX output for large docs (client-side assembly) |
| Heap (async) | 12 MB per batch execute | Batch size 1 gives fresh heap per record |
| No e-signatures | Intentionally excluded | Use DocuSign, Adobe Sign, etc. after generation |
Template (.docx/.xlsx/.pptx)
↓
Decompress → Merge XML tags → Recompress
↓ ↓
DOCX/XLSX/PPTX PDF path:
(client-side ZIP) DocGenHtmlRenderer → Blob.toPdf()
| Class | Role |
|---|---|
DocGenService |
Core merge engine — tags, loops, images, aggregates, barcodes |
DocGenHtmlRenderer |
DOCX XML → HTML for PDF rendering, barcode/QR CSS |
DocGenDataRetriever |
Multi-level SOQL with query tree stitching |
BarcodeGenerator |
Code 128 + QR code generation (pure Apex, Reed-Solomon) |
DocGenController |
LWC controller — template CRUD, generation endpoints |
DocGenBatch |
Batch Apex for bulk document generation |
docGenPdfMerger.js |
Client-side PDF merge engine (pure JS) |
docGenZipWriter.js |
Client-side Office Open XML assembly (pure JS) |
See CHANGELOG.md for full version history.
Scanned with Salesforce Code Analyzer v5.9.0 using the recommended rule selector — the same rules used by Salesforce Security Review.
| Severity | Count | Status | Notes |
|---|---|---|---|
| Critical | 0 | ✅ Pass | No security vulnerabilities |
| High | 0 | ✅ Pass | No CRUD/FLS, SOQL injection, or XSS issues |
| Moderate | 344 | ℹ️ | Cyclomatic complexity, missing braces (style only) |
| Low | 617 | ℹ️ | Missing ApexDoc, SLDS class suggestions |
| Info | 60 | ℹ️ | Trailing whitespace, copy-paste detection |
Run it yourself:
sf code-analyzer run --rule-selector "recommended" --target force-app- 507 / 507 tests passing (100% pass rate)
- 83% org-wide code coverage
- All tests use
System.runAs(), assertion messages, and real data
sf apex run --target-org <org> -f scripts/e2e-test.apex
PASS: 22 FAIL: 0 ALL TESTS PASSED
| # | Test | Result |
|---|---|---|
| T1 | Account Name field merge | PASS |
| T2 | Owner.Name parent field lookup | PASS |
| T3 | Contacts child loop (2 records) | PASS |
| T4 | Opportunities child loop (1 record) | PASS |
| T5 | Product2.Name on Line Items (parent field through child) | PASS |
| T6 | Line Items count (2 records) | PASS |
| T7 | Description ContentVersion ID (image field) | PASS |
| T8 | Legacy V1 backward compatibility | PASS |
| T9 | Image CV ID format validation | PASS |
| T10 | Image CV file accessibility | PASS |
| T11 | PDF document generation (Blob.toPdf) | PASS |
| T12 | Generated file not empty | PASS |
| T13 | Document generation size check | PASS |
| T14 | Junction stitching (OCR -> Contact) | PASS |
| T15 | COUNT:Contacts aggregate | PASS |
| T16 | SUM:LineItems.TotalPrice aggregate | PASS |
| T17 | SUM with :currency formatting | PASS |
| T18 | AVG:UnitPrice aggregate | PASS |
| T19 | MIN:Quantity aggregate | PASS |
| T20 | MAX:Quantity aggregate | PASS |
| T21 | V4 Apex Data Provider generation | PASS |
| T22 | V4 missing class error handling | PASS |
QR encoding verified module-by-module against qrcode-generator reference library for versions 1 (21x21), 3 (29x29), and 6 (41x41). All modules match. See scripts/qr-verify.js.
DocGen is now published through a Salesforce Partner org (Portwood Global Solutions). We are actively working toward listing as a Salesforce Accelerator (similar to DLRS and other community-driven tools). A community support page is in progress — stay tuned.
For questions, bugs, or feature requests:
- Email: hello@portwoodglobalsolutions.com
- GitHub Issues: github.com/DaveMoudy/SalesforceDocGen/issues
Open-source under Apache 2.0. Contributions welcome:
- Fork the repo
- Create a feature branch
- Submit a PR with a clear description
Apache License, Version 2.0. See LICENSE.
Built by Portwood Global Solutions