Erik's ToolBox Documentation
Index

Codeunit Support

ToolBox scripts can declare codeunit variables and call the member functions of a set of supported standard Business Central codeunits. This brings a large body of platform functionality — math, REST, email, document posting, address formatting, and more — into your scripts with familiar Variable.Method(...) syntax.

Declaring and Calling a Codeunit

Declare a codeunit variable in a var block with Codeunit <Subtype>, then call its members with dot notation. Subtype names that contain spaces or punctuation must be quoted.

var
    MyMath: Codeunit Math;
    Client: Codeunit "Rest Client";
begin
    Message('Square root of 2 = %1', MyMath.Sqrt(2));
    Message('Pi = %1', MyMath.Pi());
end;

The editor completes codeunit subtype names after you type the codeunit keyword, and completes member functions after a codeunit variable and a dot. See Editor.

Extensible: Codeunit support is open. Other apps register additional subtypes through the interpreter's Codeunit_Type_Hgd enum and the InterpreterCodeunit_Hgd interface, and those subtypes then appear in completion and are callable from scripts exactly like the built-in ones below.

Only the subtypes listed on this page can be declared as codeunit variables. Any other codeunit, standard or custom, can still be started by number with the Codeunit.Run(Id[, Rec]) statement, which runs its OnRun trigger and returns nothing. Codeunit variables are reference types: passing one to a procedure shares the same instance. A procedure cannot return a codeunit.

Supported Codeunits

Subtype Purpose
Math Full math library (works in Decimal)
Type Helper Date formatting, time splitting, bitwise, hex
Rest Client REST/HTTP calls
Temp Blob In-memory blob and stream creation
Base64 Convert Base64 encode/decode
Regex Regular expression match / replace / split
Data Compression Zip and gzip
Environment Information Environment / tenant facts
No. Series Number series
Language Language and culture lookups
Confirm Management Non-interactive confirmations
Sales-Post / Purch.-Post Post sales / purchase documents
Release Sales Document / Release Purchase Document Release / reopen documents
Gen. Jnl.-Post Batch Post a general journal batch
Archive Management Archive and restore documents
CheckManagement Void checks
SegManagement Log interactions and segments
Email / Email Message Compose and send email
Format Address Format postal addresses

The sections below list each codeunit's members. Parameters are shown with their types; overloads are noted where they exist.

Math

The Math codeunit is a full math library. All operations work in Decimal — inputs and return values are decimals.

Member Returns Notes
Pi() Decimal
E() Decimal
Abs(Value) Decimal
Sqrt(Value) Decimal
Pow(X, Y) Decimal X raised to Y
Exp(Value) Decimal e raised to Value
Log(Value) Decimal Natural logarithm
Log10(Value) Decimal
Sin / Cos / Tan Decimal Angle in radians
Sinh / Cosh / Tanh Decimal Hyperbolic
Asin / Acos / Atan Decimal Inverse; result in radians
Floor(Value) Decimal
Ceiling(Value) Decimal
Truncate(Value) Decimal Integer part
Sign(Value) Decimal -1, 0, or 1
BigMul(A, B) Decimal
IeeeRemainder(X, Y) Decimal
var
    M: Codeunit Math;
begin
    Message('sin(pi/2) = %1', M.Sin(M.Pi() / 2));   // 1
    Message('2^10 = %1', M.Pow(2, 10));             // 1024
    Message('ceil(4.2) = %1', M.Ceiling(4.2));      // 5
end;

Type Helper

Member Returns Notes
GetLocalizedMonthToInt(Month) Integer Localized month name to 1..12
CompareDateTime(A, B) Integer -1, 0, or 1
FormatDate(Date, Format: Integer) Text
FormatDate(Date, Format: Text, Culture: Text) Text
FormatDateWithCurrentCulture(Date) Text
GetHmsFromTime(var Hour, var Minute, var Second, Time) Split a time
AddHoursToDateTime(DateTime, Hours) DateTime
BitwiseAnd(A, B) / BitwiseOr(A, B) / BitwiseXor(A, B) Integer
IntToHex(Value) Text
var
    TH: Codeunit "Type Helper";
    H: Integer;
    M: Integer;
    S: Integer;
begin
    TH.GetHmsFromTime(H, M, S, 143005T);
    Message('%1h %2m %3s', H, M, S);                 // 14h 30m 5s
    Message('255 in hex = %1', TH.IntToHex(255));    // FF
end;

Rest Client

Makes REST/HTTP calls. Configure the client, then call a verb.

Member Returns Notes
Initialize() Reset the client
SetBaseAddress(Url)
GetBaseAddress() Text
SetTimeout(Timeout: Duration)
GetTimeout() Duration
SetAuthorizationHeader(Value)
SetDefaultRequestHeader(Name, Value)
SetUserAgentHeader(Value)
AddCertificate(Certificate) Base64-encoded certificate
Get(Path) Text GET; returns the response body
Delete(Path) Text DELETE; returns the response body
GetAsJson(Path) JsonToken GET for JSON
PostAsJson(Path, Body: JsonObject) JsonToken POST
PutAsJson(Path, Body: JsonObject) JsonToken PUT
PatchAsJson(Path, Body: JsonObject) JsonToken PATCH

Differs from standard AL: In ToolBox, Get and Delete return the response body as Text directly (not an HttpResponseMessage), and the *AsJson methods return a JsonToken. This makes the common cases one line each.

var
    Client: Codeunit "Rest Client";
    Body: JsonObject;
    Response: JsonToken;
begin
    Client.SetBaseAddress('https://api.example.com');
    Client.SetDefaultRequestHeader('Accept', 'application/json');

    // Simple GET returning text
    Message(Client.Get('/status'));

    // POST JSON, read JSON back
    Body.Add('name', 'Widget');
    Response := Client.PostAsJson('/products', Body);
    Message('Created id: %1', Response.AsObject().GetInteger('id'));
end;

Temp Blob

An in-memory blob used mainly to create streams. See Streams.

Member Returns Notes
CreateInStream(var InStream)
CreateInStream(var InStream, Encoding: Text) Encoding: utf8 (default) / utf16 / msdos / windows, or TextEncoding::UTF8 etc.
CreateOutStream(var OutStream)
CreateOutStream(var OutStream, Encoding: Text) Same encoding options
HasValue() Boolean
Length() Integer Size in bytes
FromRecordRef(Record, FieldNo) Load the blob from a record field (FromRecord is accepted as an alias)
ToRecordRef(Record, FieldNo) Store the blob into a record field

Blob fields cannot be read or assigned as values through Rec.Field, but they open streams directly: Rec.BlobField.CreateOutStream(Out) / CreateInStream(In) / HasValue / Length (see Streams). FromRecordRef/ToRecordRef remain the by-field-number alternative.

Base64 Convert

Member Returns Notes
ToBase64(Value: Text) Text Encode text
ToBase64(Value: Text, InsertLineBreaks: Boolean) Text
ToBase64(InStream) Text Encode a stream
ToBase64(InStream, InsertLineBreaks: Boolean) Text
FromBase64(Base64: Text) Text Decode to text
FromBase64(Base64: Text, OutStream) Text Decode into a stream
var
    B64: Codeunit "Base64 Convert";
    Encoded: Text;
begin
    Encoded := B64.ToBase64('Hello ToolBox');
    Message('Encoded: %1', Encoded);
    Message('Decoded: %1', B64.FromBase64(Encoded));
end;

Regex

Member Returns Notes
IsMatch(Input, Pattern) Boolean
Replace(Input, Pattern, Replacement) Text Replace every match
Split(Input, Pattern) List of [Text] Split on every match
var
    Rx: Codeunit Regex;
    Parts: List of [Text];
    Part: Text;
begin
    if Rx.IsMatch('ABC-123', '^[A-Z]+-\d+$') then
        Message('Valid code');

    Parts := Rx.Split('a1b2c3', '\d');
    foreach Part in Parts do
        Message('[%1]', Part);
end;

Data Compression

Create or open zip archives, and compress/decompress gzip streams. See Streams for a full worked example.

Member Returns Notes
CreateZipArchive() Start a new archive
OpenZipArchive(InStream) Open an existing archive
OpenZipArchive(InStream, OpenForUpdate: Boolean)
CloseZipArchive()
AddEntry(InStream, PathInArchive: Text)
GetEntryList() List of [Text] Entry names
ExtractEntry(EntryName, OutStream) Integer Returns the entry length
SaveZipArchive(OutStream) Write the archive to a stream
IsGzip(InStream) Boolean
GzipCompress(InStream, OutStream)
GzipDecompress(InStream, OutStream)

Environment Information

Read-only facts about the current environment.

Member Returns Member Returns
GetEnvironmentName() Text IsSaaS() Boolean
IsSandbox() Boolean IsOnPrem() Boolean
IsProduction() Boolean IsSaaSInfrastructure() Boolean
GetApplicationFamily() Text CanStartSession() Boolean
var
    Env: Codeunit "Environment Information";
begin
    if Env.IsSandbox() then
        Message('Running in sandbox: %1', Env.GetEnvironmentName())
    else
        Message('Running in production');
end;

No. Series

Member Returns Notes
GetNextNo(NoSeriesCode) Code Get and consume the next number
GetNextNo(NoSeriesCode, UsageDate) Code
GetNextNo(NoSeriesCode, UsageDate, HideErrorsAndWarnings) Code
PeekNextNo(NoSeriesCode) Code Preview without consuming
PeekNextNo(NoSeriesCode, UsageDate) Code

Language

Language and culture lookups.

Member Returns Member Returns
GetUserLanguageCode() Code GetDefaultApplicationLanguageId() Integer
GetLanguageId(LanguageCode) Integer ValidateApplicationLanguageId(Id)
GetLanguageIdOrDefault(LanguageCode) Integer ValidateWindowsLanguageId(Id)
GetFormatRegionOrDefault(FormatRegion) Text GetParentLanguageId(Id) Integer
GetLanguageCode(LanguageId) Code GetTwoLetterIsoLanguageName(Id) Text
GetWindowsLanguageName(LanguageCode) Text GetLanguageIdFromCultureName(Name) Integer
GetWindowsLanguageName(LanguageId) Text GetCultureName(LanguageId) Text
GetDefaultApplicationLanguageId() Integer GetCurrentCultureName() Text

Confirm Management

Get a confirmation answer that works even when no dialog can be shown (for example, in a Job Queue session).

Member Returns Notes
GetResponse(ConfirmQuestion) Boolean false when no dialog is possible
GetResponse(ConfirmQuestion, DefaultButton) Boolean
GetResponseOrDefault(ConfirmQuestion) Boolean Default when no dialog is possible
GetResponseOrDefault(ConfirmQuestion, DefaultButton) Boolean

Document Posting and Release

These codeunits take Record arguments — declare a record variable, load the document, and pass it.

Sales-Post / Purch.-Post

Codeunit Member Returns Notes
Sales-Post SetSuppressCommit(Suppress)
Sales-Post Run(SalesHeader: Record) Boolean Post a sales document
Purch.-Post SetSuppressCommit(Suppress)
Purch.-Post Run(PurchaseHeader: Record) Boolean Post a purchase document
var
    SalesHeader: Record "Sales Header";
    Poster: Codeunit "Sales-Post";
begin
    SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order);
    if SalesHeader.FindFirst() then begin
        Poster.SetSuppressCommit(false);
        if Poster.Run(SalesHeader) then
            Message('Posted order %1', SalesHeader."No.");
    end;
end;

Release Sales Document / Release Purchase Document

Member Returns Notes
Run(Header: Record) Boolean Release with full checks
PerformManualRelease(Header)
PerformManualReopen(Header)
Reopen(Header)

Gen. Jnl.-Post Batch

Member Returns Notes
Run(GenJournalLine: Record) Boolean Post the journal batch the line belongs to

Archive Management

Member Notes
ArchiveSalesDocument(SalesHeader) Archive with confirmation
ArchSalesDocumentNoConfirm(SalesHeader) Archive without confirmation
AutoArchiveSalesDocument(SalesHeader) Archive according to setup
StoreSalesDocument(SalesHeader, InteractionExist)
ArchivePurchDocument(PurchaseHeader) Archive with confirmation
ArchPurchDocumentNoConfirm(PurchaseHeader) Archive without confirmation
AutoArchivePurchDocument(PurchaseHeader) Archive according to setup
StorePurchDocument(PurchaseHeader, InteractionExist)
RestoreSalesDocument(SalesHeaderArchive) Restore from an archive

CheckManagement

Member Notes
VoidCheck(GenJournalLine) Void the check on a payment journal line
FinancialVoidCheck(CheckLedgerEntry) Financially void a posted check

SegManagement

Member Returns Notes
LogDocument(DocumentType, DocumentNo, DocNoOccurrence, VersionNo, AccountTableNo, AccountNo, SalespersonCode, CampaignNo, Description, OpportunityNo) Integer Log a document interaction; returns the entry no.
FindInteractionTemplateCode(DocumentType) Code Template for a document type
LogSegment(SegmentHeader, Deliver, Followup) Log a segment and its lines

Email and Email Message

Compose a message (optionally with attachments) and send it.

Email Message

Member Notes
Create(To, Subject, Body) Recipients separated by semicolons
Create(To, Subject, Body, HtmlFormatted)
AddAttachment(Name, ContentType, Base64: Text)
AddAttachment(Name, ContentType, InStream)
GetSubject() Returns Text
GetBody() Returns Text

Email

Member Returns Notes
Send(Message: Codeunit "Email Message") Boolean Send a composed message
Send(To, Subject, Body) Boolean
Send(To, Subject, Body, HtmlFormatted) Boolean
var
    Msg: Codeunit "Email Message";
    Mail: Codeunit Email;
begin
    Msg.Create('user@example.com', 'ToolBox report', '<h1>Done</h1>', true);
    Msg.AddAttachment('report.txt', 'text/plain', 'UmVwb3J0');   // base64 content
    if Mail.Send(Msg) then
        Message('Email sent');
end;

Format Address

Formats postal addresses. Each method has two calling shapes:

  1. Native array form — the first argument is a var AddrArray: array[8] of Text that the

method fills, exactly like real AL. It has no meaningful return value.

  1. Text/record-only form — omit the array; the method returns the compressed address lines

as a List of [Text].

Member Text-only returns Notes
FormatAddr(Name, Name2, Contact, Addr, Addr2, City, PostCode, County, CountryCode) List of [Text] Free-field address
UseCounty(CountryCode) Boolean Whether county is shown for a country
Company(CompanyInformation) List of [Text]
Customer(Customer) List of [Text]
Vendor(Vendor) List of [Text]
BankAcc(BankAccount) List of [Text]
Location(Location) List of [Text]
ContactAddr(Contact) List of [Text]
Employee(Employee) List of [Text]
SalesHeaderSellTo / SalesHeaderBillTo / SalesHeaderShipTo (SalesHeader) List of [Text] Sales order addresses
PurchHeaderBuyFrom / PurchHeaderPayTo / PurchHeaderShipTo (PurchaseHeader) List of [Text] Purchase order addresses
SalesInvSellTo / SalesInvBillTo / SalesInvShipTo (SalesInvoiceHeader) List of [Text] Posted sales invoice addresses
PurchInvBuyFrom / PurchInvPayTo / PurchInvShipTo (PurchInvHeader) List of [Text] Posted purchase invoice addresses

The *ShipTo overloads on SalesHeader/SalesInvoiceHeader take an extra CustAddr: array[8] of Text in their native array form (ship-to differs from the customer address) and return Boolean.

var
    Formatter: Codeunit "Format Address";
    Customer: Record Customer;
    Lines: List of [Text];
    Line: Text;
    AddrArray: array[8] of Text;
    I: Integer;
begin
    Customer.Get('10000');

    // Text-only form -> List of [Text]
    Lines := Formatter.Customer(Customer);
    foreach Line in Lines do
        Message('%1', Line);

    // Native array form -> fills AddrArray
    Formatter.Customer(AddrArray, Customer);
    for I := 1 to ArrayLen(AddrArray) do
        if AddrArray[I] <> '' then
            Message('Line %1: %2', I, AddrArray[I]);
end;