SfSkills Domains Docs GitHub

Home / apex / fsl-service-report-templates

fsl-service-report-templates

Use this skill when designing, generating, or troubleshooting Field Service service report templates — covers the createServiceReport REST action (API v40.0+), ServiceReportLayout configuration, DigitalSignature capture, Document Builder (Winter '25+) with conditional logic via Flow, and PDF storage as ContentDocument/ContentVersion. NOT for Quote PDF templates — use apex/quote-pdf-customization. NOT for Visualforce PDF generation — use apex/pdf-generation-patterns.

Open the skill folder on GitHub


FSL Service Report Templates

This skill activates when building, generating, or troubleshooting Field Service service reports — including Apex-driven generation via the ConnectApi.FieldService namespace, ServiceReportLayout setup, customer signature capture via DigitalSignature, offline PDF gaps, and the newer Document Builder (Winter '25+) path for conditional report sections.


Before Starting

Gather this context before working on anything in this domain:


Core Concepts

ServiceReportLayout — The Classic Template Builder

Service report templates are stored as ServiceReportLayout records and configured in Setup under Field Service > Service Report Templates. The builder provides a drag-and-drop canvas. Supported sections include:

Templates are associated with Work Types or applied as defaults. A single org can have multiple layouts for different work categories (installation vs. maintenance vs. inspection).

Limitation: Conditional section visibility is not supported in the classic builder. All sections in a template always render. This is a known platform gap documented in the FSL Developer Guide.

createServiceReport — Apex and REST Generation

Service reports are generated programmatically via:

ConnectApi.ServiceReport result =
    ConnectApi.FieldService.createServiceReport(serviceAppointmentId, serviceReportTemplateId);

Or equivalently via REST Composite/sObject API as a named action against a WorkOrder or ServiceAppointment record. Both paths require API v40.0+. The generated PDF is automatically stored as a ContentDocument / ContentVersion linked to the source record (WorkOrder or ServiceAppointment) via a ContentDocumentLink.

The serviceReportTemplateId is the Id of the ServiceReportLayout record to render. If omitted, the platform uses the default template associated with the related Work Type, falling back to the org-level default.

Apex invocation runs synchronously for records with modest field counts but can be slow (2–5 seconds) for data-heavy reports. Trigger contexts with tight CPU limits should invoke it asynchronously via a Queueable.

DigitalSignature — Customer and Technician Signatures

Customer and technician signatures collected on the FSL mobile app are stored as DigitalSignature SObject records. Each DigitalSignature record is linked to the parent WorkOrder or ServiceAppointment via a lookup and stores:

The ServiceReportLayout signature placeholder reads from linked DigitalSignature records when rendering the PDF. If the signature was collected offline and not yet synced, the signature block renders blank. Signature capture must occur before createServiceReport is called to appear in the rendered output.

Document Builder — Conditional and Dynamic Reports (Winter '25+)

Document Builder (Setup > Document Builder) is the newer platform feature for PDF generation across multiple objects. For FSL, it provides:

Document Builder templates are separate from ServiceReportLayout records. They are configured in Setup as Document Builder templates and linked to objects (WorkOrder, ServiceAppointment). Generated PDFs are stored as ContentDocument/ContentVersion, same as classic reports. For new implementations requiring conditional logic, Document Builder is the recommended path.


Common Patterns

Pattern 1: Apex-Driven Report Generation on Status Change

When to use: Automatically generate and attach a service report PDF when a ServiceAppointment status transitions to Completed.

How it works:

  1. An Apex trigger (or Record-Triggered Flow calling an Apex action) fires on ServiceAppointment update.
  2. It checks Status == 'Completed' and Status_old != 'Completed'.
  3. It enqueues a Queueable to avoid CPU limit pressure from synchronous PDF rendering.
  4. The Queueable calls ConnectApi.FieldService.createServiceReport(saId, templateId).
  5. The resulting ContentDocument is automatically linked to the ServiceAppointment.
public class ServiceReportQueueable implements Queueable {
    private Id serviceAppointmentId;
    private Id templateId;

    public ServiceReportQueueable(Id saId, Id tplId) {
        this.serviceAppointmentId = saId;
        this.templateId = tplId;
    }

    public void execute(QueueableContext ctx) {
        ConnectApi.FieldService.createServiceReport(
            serviceAppointmentId,
            templateId
        );
    }
}

Why not synchronous trigger: createServiceReport performs a REST callout internally and is slow (2–5 s). Calling it synchronously in a before/after trigger risks hitting governor limits for bulk operations and can cause lock contention on the ContentDocument table.

Pattern 2: Document Builder with Flow-Driven Conditional Sections

When to use: Report template needs sections that appear only for certain work types or field values (e.g., show a safety checklist section only for electrical work orders).

How it works:

  1. Create a Document Builder template in Setup, pointing at WorkOrder or ServiceAppointment.
  2. Define conditional section visibility rules using Decision elements in a Flow embedded in the template.
  3. Create a Record-Triggered Flow on the source record to auto-generate via the Document Builder Generate action.
  4. The generated PDF is stored as ContentDocument linked to the record.

Why not classic ServiceReportLayout: Classic templates have no conditional rendering capability. Every configured section always appears in the output regardless of record data. Document Builder is the only supported path for conditional content.


Decision Guidance

SituationRecommended ApproachReason
Basic report with fixed sections, no conditional logicClassic ServiceReportLayout + createServiceReport ApexSimpler to configure, GA since API v40.0, well understood
Conditional section visibility requiredDocument Builder (Winter '25+)Classic builder has no conditional section support
LWC-embedded custom UI in reportDocument BuilderClassic layouts cannot embed LWC components
Customer signature capture on mobileClassic ServiceReportLayout with DigitalSignature placeholderSignatures in DigitalSignature object render natively in classic layout
Offline report generation on mobile appEnsure Briefcase Builder primes all fields used in the templateOffline PDFs blank fields not in Briefcase priming config
Programmatic generation from ApexConnectApi.FieldService.createServiceReport() in a QueueableAvoids CPU limits; runs async outside trigger context
Quote or proposal PDFUse a separate CPQ or Proposal template toolService reports are NOT quote templates

Step-by-step instructions for an AI agent or practitioner working on this task:

  1. Clarify requirements — Determine target record (WorkOrder vs. ServiceAppointment), whether signature capture is needed, whether conditional sections are required, and whether offline generation on mobile must be supported.
  2. Choose template approach — If conditional sections or LWC embedding are required, use Document Builder (Winter '25+). Otherwise, configure a ServiceReportLayout in Setup under Field Service > Service Report Templates.
  3. Configure the template layout — Drag and drop field sections, related lists (Products Consumed, Time Sheets), signature placeholders, and header/footer elements. Associate the template with the relevant Work Type or set it as the org default.
  4. Implement Apex or Flow generation — For automated generation, implement a Queueable Apex class calling ConnectApi.FieldService.createServiceReport(recordId, templateId) triggered from a Record-Triggered Flow or trigger on status change to Completed. For Document Builder, configure a Record-Triggered Flow using the Document Builder Generate action.
  5. Configure signature capture — If customer signatures are required, ensure the ServiceReportLayout includes a signature placeholder (or Document Builder section references DigitalSignature). Verify the DigitalSignature record is created and synced before the report generation action fires.
  6. Address offline requirements — If mobile technicians generate reports offline, open Briefcase Builder and verify every field referenced in the report template is included in the priming rules. Missing fields render blank in offline PDFs.
  7. Validate and test — Generate a test report on a WorkOrder/ServiceAppointment in a sandbox. Confirm ContentDocument is linked, PDF is not blank, signature image appears, and all expected sections render correctly.

Review Checklist

Run through these before marking work in this area complete:


Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

  1. Conditional sections are not supported in classic ServiceReportLayout — The Setup drag-and-drop builder has no conditional visibility controls. Every section in the template always renders regardless of record data. If you need conditional sections, migrate to Document Builder (Winter '25+). Attempting to work around this with empty sections or placeholder text causes cluttered reports with no clean solution in the classic builder.
  2. Offline PDF blanks fields not in Briefcase priming — When a technician is offline and generates a service report via the FSL mobile app, the PDF is rendered from locally cached data only. Any field not included in the Briefcase Builder priming configuration will render as blank in the PDF. This is not a template defect — it is a data availability issue. Fix: audit the template fields against Briefcase Builder priming rules and add any missing field references.
  3. Signature must be captured before report generation — The DigitalSignature record must exist and be synced to the server before createServiceReport is called. If the report is auto-generated immediately on status change (e.g., via a trigger on Completed), the signature may not yet be synced if the technician is on a slow connection. Solution: add a short delay (Scheduled Flow), check for signature existence before generating, or allow manual re-generation.

Output Artifacts

ArtifactDescription
fsl-service-report-templates-template.mdWork template for designing and implementing a service report template — captures requirements, layout decisions, and generation approach
check_service_report.pyStdlib-only validator that checks Apex classes for common anti-patterns in service report generation (synchronous calls, missing Queueable pattern)


Official Sources Used

Dependencies

Package files