Skip to main content

AL Coding Standards

This page documents the AL coding patterns and conventions used across all Bestway BC extensions. These are the positive patterns — the "how we do things here." For anti-patterns and what to avoid, see the Contribution Guidelines.

Extension Configuration

Required app.json Fields

Every extension's app.json must include:

FieldDetails
nameShort, descriptive extension name
publisherPublisher organization
versionFour-part version (major.minor.patch.build) — must match all documentation
idRangesReserved, non-overlapping ID ranges for all objects
dependenciesComplete list of extension dependencies with correct app IDs and versions
featuresMust include "NoImplicitWith"
applicationInsightsConnectionStringBestway's shared Azure Application Insights connection string
resourceExposurePolicyallowDebugging, allowDownloadingSource, and includeSourceInSymbolFile all set to true

Object ID Ranges

Each extension has a reserved, non-overlapping range of IDs defined in idRanges. All new objects — tables, pages, codeunits, enums, permission sets — must use IDs within the assigned range. Never reuse IDs across extensions. If you are running low on available IDs, request an expanded range before proceeding.

Check the idRanges in the extension's app.json and its README for the next available ID.

Telemetry

All extensions must include extension-level telemetry via applicationInsightsConnectionString in app.json. This sends extension-emitted events to Bestway's centralized Azure Application Insights resource. The connection string will be provided at the start of the engagement. This is not optional.


File Organization

Folder Structure

Extensions organize AL objects by type in dedicated subfolders under src/:

ExtensionFolder/
├── docs/
│ ├── CHANGELOG.md
│ └── CHANGE-v{version}.md
├── src/
│ ├── Codeunit/
│ ├── Table/
│ ├── TableExt/
│ ├── Page/
│ ├── PageExt/
│ ├── Enum/
│ ├── EnumExt/
│ ├── PermissionSet/
│ ├── Report/
│ └── ReportExt/
├── app.json
└── README.md

Legacy extensions may use different conventions (lowercase pluralized folders, flat structures without src/). The structure above applies to all new extensions and major refactors. When modifying an existing extension, follow the convention already established within that extension for consistency.

File Naming

Files follow the convention {Prefix}{ObjectName}.{ObjectType}.al:

  • PhoneIntegration.Codeunit.al
  • NextivaConfig.Table.al
  • NextivaSetupPage.Page.al

Namespace Declarations

Extensions targeting application: 27.0.0.0 or later should include namespace declarations (e.g., namespace BestwayUSA.bccsmapi;). Extensions targeting earlier versions may omit namespaces.

Naming Prefixes

  • INVC prefix: Used on all BestwayUSA core custom objects and fields (originally from Innovia Consulting — e.g., INVCSerialNo.Table.al, INVCCustomerCard.PageExt.al)
  • Custom enums: Use the INVC prefix for BestwayUSA enums (e.g., INVCDocumentAttachmentType, INVCWarrantyType)

Architecture Patterns

Business Logic in Codeunits

Business logic belongs in codeunits, not page or report triggers. This is the primary architectural rule for testability.

Page triggers should call codeunit procedures. This pattern enables:

  • Unit testing of the logic without a UI dependency
  • Reuse of the same logic across multiple pages
  • Cleaner separation of concerns

Example pattern — the CSM API extension extracts computed fields into a helper codeunit:

CSM API Helper (Codeunit 56104)
├── GetOrderStatus() → translates BC status codes to API-friendly strings
├── GetAttachmentUrl() → builds blob storage URLs
└── FormatPhoneNumber() → normalizes phone formats

CSM API pages call the helper rather than implementing logic directly.

Event Subscribers for Cross-Extension Integration

Event subscribers are the standard mechanism for cross-extension integration in this repo:

  • INVCGeneralEvents.Codeunit.al — defines integration events
  • INVCSalesHandler.Codeunit.al — subscribes to sales-related events

When an extension needs to respond to events from another extension, implement an event subscriber rather than modifying the source extension.

Test Design

Test codeunits follow these conventions:

  • Use the [Test] attribute on each test procedure
  • Structure each test with Given / When / Then comment blocks
  • Use TestPage for functional tests that verify UI behavior
  • Use Library Assert for assertions
  • Tests use BC's auto-rollback transaction model — test data is cleaned up automatically
  • Run tests via the BC Test Tool (page 130401)

Version Numbering

Use four-part versioning: major.minor.patch.build.

The version in app.json must match the version referenced in all documentation (CHANGELOG, CHANGE documents, test plans). Bump the version for every deliverable — there should never be a delivery without a corresponding version increment.