Cloud Events Setup Reference

Overview

The Cloud Events Setup provides centralized configuration for selecting implementation strategies for various message types. This document explains how to configure the setup table, select implementations through enums, and understand the interface-based architecture.

Namespace: Origo.PTE.CloudEvents Setup Table: Cloud Events Setup (Table 65302) Setup Page: Cloud Events Setup (Page 65302)


Setup Architecture

The Cloud Events extension uses an interface-based architecture where:

  1. Interfaces define contracts that implementations must follow
  2. Enums provide selection options that implement specific interfaces
  3. Setup Table stores the selected enum value for each feature area
  4. Message Type Implementations retrieve the selected interface from setup

This design allows:


Configuration Fields

1. Customer Credit Limit Type

Field: Customer Credit Limit Type (Field 10) Type: Enum Customer Credit Limit Type (Enum 65303) Interface: Customer Credit Limit (Interface) Related Message Type: Customer.CreditLimit.Get

Purpose: Determines how customer credit limit calculations are performed for the Customer.CreditLimit.Get message type.

Available Values:

ValueCaptionImplementationDescription
0DefaultDefault Credit Limit ImplStandard Business Central credit limit calculation

Extensibility:

enumextension 50100 "My Credit Limit Type" extends "Customer Credit Limit Type"
{
    value(50100; "Enhanced Credit Check")
    {
        Caption = 'Enhanced Credit Check';
        Implementation = "Customer Credit Limit" = "My Credit Limit Impl";
    }
}

2. Credit Limit Tolerance %

Field: Credit Limit Tolerance % (Field 11) Type: Decimal Range: 0 to 100 Decimal Places: 0:2

Purpose: Defines the tolerance percentage for credit limit exceedance checks. This value adds flexibility to credit limit enforcement by allowing a percentage buffer above the strict credit limit.

How It Works:

When checking if a customer has exceeded their credit limit:

  1. Base Calculation:
  1. With Tolerance:

Example:

Given:

Calculation:

Use Cases:

Related Response Fields:

The Customer.CreditLimit.Get message type returns:


3. Item Calc. Availability Type

Field: Item Calc. Availability Type (Field 12) Type: Enum Item Calc. Availability Type (Enum 65304) Interface: Item Calc. Availability (Interface) Related Message Type: Item.Availability.Get

Purpose: Determines how item availability is calculated for the Item.Availability.Get message type.

Available Values:

ValueCaptionImplementationDescription
0Physical InventoryPhysical Inventory ImplReturns actual physical inventory quantity by location
1Calculated QuantityCalculated Quantity ImplReturns calculated available quantity considering supply and demand

Implementation Details:

Physical Inventory

Response Format:

{
  "status": "Success",
  "itemNo": "1000",
  "itemDescription": "Bicycle",
  "baseUnitOfMeasure": "PCS",
  "inventory": [
    { "locationCode": "BLUE", "inventory": 50 },
    { "locationCode": "RED", "inventory": 30 }
  ]
}

Calculated Quantity

Response Format:

{
  "status": "Success",
  "itemNo": "1000",
  "itemDescription": "Bicycle",
  "baseUnitOfMeasure": "PCS",
  "requestedDeliveryDate": "2026-03-15",
  "availability": [
    {
      "locationCode": "BLUE",
      "inventory": 50,
      "reserved": 10,
      "grossRequirement": 20,
      "scheduledReceipt": 30,
      "plannedOrderReceipt": 15,
      "projectedAvailableBalance": 65
    }
  ]
}

Extensibility:

enumextension 50101 "My Availability Type" extends "Item Calc. Availability Type"
{
    value(50100; "Custom ATP")
    {
        Caption = 'Custom Available to Promise';
        Implementation = "Item Calc. Availability" = "My ATP Impl";
    }
}

4. Item Price Calculation Type

Field: Item Price Calculation Type (Field 13) Type: Enum Item Price Calculation Type (Enum 65305) Interface: Item Price Calculation (Interface) Related Message Type: Item.Price.Get

Purpose: Determines how item price information is calculated for the Item.Price.Get message type.

Available Values:

ValueCaptionImplementationDescription
0DefaultDefault Price ImplStandard price list retrieval with customer-specific pricing support

Implementation Details:

The Default Price Implementation provides:

Price Selection Logic:

  1. Customer-Specific Prices:
  1. All-Customers Prices:
  1. Item Card Prices:

Request Parameters:

{
  "itemNo": "1000",
  "customerNo": "C001",
  "requestedDeliveryDate": "2026-03-15",
  "quantity": 10,
  "variantCode": "BLUE"
}

Response Format:

{
  "status": "Success",
  "itemNo": "1000",
  "itemDescription": "Bicycle",
  "baseUnitOfMeasure": "PCS",
  "customerNo": "C001",
  "requestedDeliveryDate": "2026-03-15",
  "priceListLines": [
    {
      "priceListCode": "RETAIL-2026",
      "priceListDescription": "Retail Price List 2026",
      "lineNo": 10000,
      "assetNo": "1000",
      "variantCode": "BLUE",
      "unitOfMeasureCode": "PCS",
      "qtyPerUnitOfMeasure": 1.0,
      "minimumQuantity": 10,
      "amountType": "Price",
      "unitPrice": 950.00,
      "unitPriceExclVAT": 950.00,
      "unitPriceInclVAT": 1178.00,
      "lineDiscountPct": 5.0,
      "allowInvoiceDisc": true,
      "allowLineDisc": true,
      "vatBusPostingGr": "DOMESTIC",
      "vatProdPostingGr": "STANDARD",
      "vatPct": 24.0,
      "priceType": "Customer",
      "status": "Active",
      "startingDate": "2026-01-01",
      "endingDate": "2026-12-31"
    }
  ]
}

Extensibility:

enumextension 50102 "My Price Type" extends "Item Price Calculation Type"
{
    value(50100; "ERP Integration")
    {
        Caption = 'External ERP Pricing';
        Implementation = "Item Price Calculation" = "My ERP Price Impl";
    }
}

5. Default Language Code

Field: Default Language Code (Field 14) Type: Code[10] Table Relation: Language.Code Related Message Types: Help.Tables.Get, Help.Fields.Get, and all message types that return language-specific captions

Purpose: Specifies the default language used when executing cloud message tasks that return language-specific text (such as captions, descriptions, and field labels). This field provides a system-wide fallback when the lcid (Windows Language ID) is not specified in the CloudEvents message.

How It Works:

The Cloud Events extension supports language-specific responses through a two-tier approach:

  1. Primary: CloudEvents Message-Level lcid
  1. Fallback: Default Language Code

Validation:

The field includes validation to ensure data integrity:

trigger OnValidate()
var
    Language: Record Language;
begin
    if "Default Language Code" <> '' then begin
        Language.Get("Default Language Code");
        Language.TestField("Windows Language ID");
    end;
end;

This ensures:

GetDefaultLanguageId() Procedure:

The setup table provides a helper procedure to retrieve the language ID:

procedure GetDefaultLanguageId(): Integer
var
    Language: Record Language;
begin
    GetRecordOnce();
    if "Default Language Code" = '' then
        exit(1033);  // English - United States
    
    if not Language.Get("Default Language Code") then
        exit(1033);
    
    exit(Language."Windows Language ID");
end;

Common Language Codes:

Language CodeWindows Language IDDescription
ENU1033English - United States
ISL1039Icelandic
DEU1031German
FRA1036French
ESP1034Spanish
SVE1053Swedish
NOR1044Norwegian (Bokmal)
DAN1030Danish

CloudEvents API Integration:

When queuing a message through the Cloud Event Queue API, you can specify the language at the message level:

{
  "specversion": "1.0",
  "type": "Help.Tables.Get",
  "source": "/myapp/inventory",
  "id": "A234-1234-1234",
  "time": "2026-03-15T10:00:00Z",
  "datacontenttype": "application/json",
  "lcid": 1039,
  "data": {}
}

If lcid is not specified, the Default Language Code from setup is used.

Use Cases:

  1. Multi-Language Deployments:
  1. API Simplification:
  1. Testing and Development:
  1. Help Documentation Retrieval:

Example Scenario:

Configuration:

Message Request (without lcid):

{
  "type": "Help.Tables.Get",
  "data": {}
}

Result:

Message Request (with lcid):

{
  "type": "Help.Tables.Get",
  "lcid": 1033,
  "data": {}
}

Result:

Related Message Types:

All message types that return language-specific content respect the Default Language Code:

Notes:


6. Customer Statement Type

Field: Customer Statement Type (Field 15) Type: Enum Customer Statement Type (Enum 65306) Interface: Customer Statement (Interface) Related Message Type: Customer.Statement.Pdf

Purpose: Determines which implementation is used to generate customer statement PDFs for the Customer.Statement.Pdf message type. This field makes statement generation pluggable — custom implementations can generate statements from alternative sources without modifying the base code.

Available Implementations:

ValueNameImplementationDescription
0Standard StatementStandard Statement ImplUses BC Report Selections for C.Statement to generate the PDF

Extending Customer Statement Type:

To add a custom implementation, create an enum extension and a codeunit implementing the Customer Statement interface:

enumextension 50100 "My Statement Type" extends "Customer Statement Type"
{
    value(50100; "Custom Statement")
    {
        Caption = 'Custom Statement';
        Implementation = "Customer Statement" = "My Custom Statement Impl";
    }
}

Default Value: Standard Statement (value 0) — uses the configured Report Selection for C.Statement.


7. ChangeLog Write Guard

Field: ChangeLog Write Guard (Field 17) Type: Enum ChangeLog Write Guard Type (Enum 65308) Interface: ChangeLog Write Guard (Interface) Related Message Type: Data.Records.Set, ChangeLog.Field.Restore

Purpose: Controls which fields Data.Records.Set may write to. When active, the guard checks every target field against the BC Change Log Setup before the write is executed.

Available Values:

ValueCaptionBehaviour
0OpenAll fields may be written — same as pre-guard behaviour. Default.
1BlockedOnly fields covered by Change Log Modification tracking may be written. All others are rejected.
2Via forceSame as Blocked but the restriction can be bypassed by including "force": true in the request and holding the CE Force Access permission set.

Validation:

Changing the guard to Blocked or Via force requires that the BC Change Log feature is active:

trigger OnValidate()
begin
    if Rec."ChangeLog Write Guard" in [Blocked, "Via force"] then
        if not ChangeLogSetup.Get() or not ChangeLogSetup."Change Log Activated" then
            Error(ChangeLogNotEnabledErr);
end;

**Using force bypass (Via force mode only):**

{
  "specversion": "1.0",
  "type": "Data.Records.Set",
  "source": "MyApp v1.0",
  "subject": "Customer",
  "data": "{\"force\":true,\"data\":[{\"id\":\"...\",\"fields\":{\"Name\":\"New Name\"}}]}"
}

The force key is a top-level boolean inside the data JSON (alongside the data array). Without the CE Force Access permission set the request is rejected even with force: true.

Checking field coverage:

Before writing, use ChangeLog.Field.Enabled to verify that a field is covered:

{ "type": "ChangeLog.Field.Enabled", "data": "{\"tableName\":\"Customer\",\"fieldNo\":2}" }

If fieldCovered is false and the guard is Blocked or Via force, the write will be rejected unless force: true is used (Via force only).

Extensibility:

enumextension 50103 "My Guard Type" extends "ChangeLog Write Guard Type"
{
    value(50100; "Custom Guard")
    {
        Caption = 'Custom Guard';
        Implementation = "ChangeLog Write Guard" = "My Custom Guard Impl";
    }
}

8. Export Company Name Type

Field: Export Company Name Type (Field 18) Type: Enum Cloud Event Company Name Type (Enum 65601) Interface: Cloud Event Company Name Related Message Types: CSV.Records.Get, CSV.DeletedRecords.Get

Purpose: Selects which company name is written to the $Company column of CSV exports. The setup field controls a single, system-wide choice that both CSV exporters resolve once per request (so every row in a single export shares the same value).

Available Values:

ValueCaptionImplementationBehaviour
0Company NameDefault Company Name Impl (65602)Returns CompanyName() (the technical Company.Name). Default. Stable across renames of the display name.
1Company Display NameDisplay Company Name Impl (65603)Returns Company."Display Name". When the display name is blank, falls back to CompanyName() so the $Company column is never empty.

When to use each value:

Resolution:

var
    CloudEventsSetup: Record "Cloud Events Setup";
    ExportCompanyName: Text[250];
begin
    ExportCompanyName := CloudEventsSetup.GetExportCompanyName();
end;

Both CSV implementations call GetExportCompanyName() once per request and reuse the value for every row written to the $Company column.

Extensibility:

enumextension 50104 "My Company Name Type" extends "Cloud Event Company Name Type"
{
    value(50100; "Legal Name")
    {
        Caption = 'Legal Name';
        Implementation = "Cloud Event Company Name" = "My Legal Name Impl";
    }
}

codeunit 50104 "My Legal Name Impl" implements "Cloud Event Company Name"
{
    procedure GetCompanyName(): Text[250]
    var
        Company: Record Company;
    begin
        Company.SetLoadFields("Legal Name");
        if Company.Get(CompanyName()) and (Company."Legal Name" <> '') then
            exit(CopyStr(Company."Legal Name", 1, 250));
        exit(CopyStr(CompanyName(), 1, 250));
    end;
}

Setup Procedures

GetRecordOnce()

Purpose: Ensures the setup record is loaded only once per transaction.

Behavior:

Usage:

CloudEventsSetup.GetRecordOnce();

InsertIfNotExists()

Purpose: Creates the setup record if it doesn't exist.

Behavior:

Usage:

CloudEventsSetup.InsertIfNotExists();

Note: This is typically called during installation.


GetCustomerCreditLimitInterface()

Purpose: Retrieves the selected Customer Credit Limit implementation.

Returns: Interface Customer Credit Limit

Behavior:

  1. Loads only the Customer Credit Limit Type field (optimized)
  2. Calls GetRecordOnce() to ensure record exists
  3. Returns the enum value as an interface

Usage:

var
    CreditLimitInterface: Interface "Customer Credit Limit";
    CloudEventsSetup: Record "Cloud Events Setup";
begin
    CreditLimitInterface := CloudEventsSetup.GetCustomerCreditLimitInterface();
    CreditLimitInterface.CheckCreditLimit(Argument);
end;

Implementation in Message Type:

internal procedure ExecuteCloudEventTask(var Argument: Record "Cloud Event Message Argument")
var
    CloudEventsSetup: Record "Cloud Events Setup";
    CreditLimitInterface: Interface "Customer Credit Limit";
begin
    // Get the configured interface implementation
    CreditLimitInterface := CloudEventsSetup.GetCustomerCreditLimitInterface();
    
    // Execute using the selected implementation
    CreditLimitInterface.CheckCreditLimit(Argument);
end;

GetItemCalculateAvailabilityInterface()

Purpose: Retrieves the selected Item Calculate Availability implementation.

Returns: Interface Item Calc. Availability

Behavior:

  1. Loads only the Item Calc. Availability Type field (optimized)
  2. Calls GetRecordOnce() to ensure record exists
  3. Returns the enum value as an interface

Usage:

var
    AvailabilityInterface: Interface "Item Calc. Availability";
    CloudEventsSetup: Record "Cloud Events Setup";
begin
    AvailabilityInterface := CloudEventsSetup.GetItemCalculateAvailabilityInterface();
    AvailabilityInterface.CalculateAvailability(Argument);
end;

GetItemPriceCalculationInterface()

Purpose: Retrieves the selected Item Price Calculation implementation.

Returns: Interface Item Price Calculation

Behavior:

  1. Loads only the Item Price Calculation Type field (optimized)
  2. Calls GetRecordOnce() to ensure record exists
  3. Returns the enum value as an interface

Usage:

var
    PriceInterface: Interface "Item Price Calculation";
    CloudEventsSetup: Record "Cloud Events Setup";
begin
    PriceInterface := CloudEventsSetup.GetItemPriceCalculationInterface();
    PriceInterface.CalculateItemPrice(Argument);
end;

GetCustomerStatementInterface()

Purpose: Retrieves the selected Customer Statement implementation.

Returns: Interface Customer Statement

Behavior:

  1. Loads only the Customer Statement Type field (optimized)
  2. Calls GetRecordOnce() to ensure record exists
  3. Returns the enum value as an interface

Usage:

var
    StatementInterface: Interface "Customer Statement";
    CloudEventsSetup: Record "Cloud Events Setup";
begin
    StatementInterface := CloudEventsSetup.GetCustomerStatementInterface();
    StatementInterface.GetCustomerStatement(Argument);
end;

GetCompanyNameInterface()

Purpose: Retrieves the selected Cloud Event Company Name implementation.

Returns: Interface Cloud Event Company Name

Behavior:

  1. Loads only the Export Company Name Type field (optimized)
  2. Calls GetRecordOnce() to ensure the setup record exists
  3. Returns the enum value as an interface

Usage:

var
    CompanyNameInterface: Interface "Cloud Event Company Name";
    CloudEventsSetup: Record "Cloud Events Setup";
begin
    CompanyNameInterface := CloudEventsSetup.GetCompanyNameInterface();
end;

GetExportCompanyName()

Purpose: Convenience wrapper that resolves the configured implementation and returns the company name for the $Company column.

Returns: Text[250]

Behavior:

  1. Calls GetCompanyNameInterface() to obtain the configured implementation
  2. Invokes GetCompanyName() on it
  3. Returns the resulting text (never blank — the Display Name implementation falls back to CompanyName())

Usage:

var
    CloudEventsSetup: Record "Cloud Events Setup";
    ExportCompanyName: Text[250];
begin
    ExportCompanyName := CloudEventsSetup.GetExportCompanyName();
end;

Callers should resolve this once per request and reuse the value for every row in a single export.


Interface Architecture

Interface Definition Pattern

Each feature area defines an interface that all implementations must follow:

Example: Item Calc. Availability Interface

interface "Item Calc. Availability"
{
    /// <summary>
    /// Calculates item availability based on the implementation strategy.
    /// </summary>
    /// <param name="Argument">Message argument containing request/response data</param>
    procedure CalculateAvailability(var Argument: Record "Cloud Event Message Argument")
}

Enum Implementation Pattern

Enums implement the interface and specify which codeunit provides the implementation:

Example: Item Calc. Availability Type Enum

enum 65304 "Item Calc. Availability Type" implements "Item Calc. Availability"
{
    Extensible = true;
    DefaultImplementation = "Item Calc. Availability" = "Physical Inventory Impl";

    value(0; "Physical Inventory")
    {
        Caption = 'Physical Inventory';
        Implementation = "Item Calc. Availability" = "Physical Inventory Impl";
    }
    value(1; "Calculated Quantity")
    {
        Caption = 'Calculated Quantity';
        Implementation = "Item Calc. Availability" = "Calculated Quantity Impl";
    }
}

Implementation Codeunit Pattern

Implementation codeunits implement the interface:

Example: Physical Inventory Implementation

codeunit 65321 "Physical Inventory Impl" implements "Item Calc. Availability"
{
    procedure CalculateAvailability(var Argument: Record "Cloud Event Message Argument")
    var
        Item: Record Item;
        RequestJson: JsonObject;
        ItemNo: Code[20];
    begin
        // Parse request
        RequestJson := Argument.GetRequestJson();
        ItemNo := GetItemNoFromRequest(RequestJson, Argument);
        
        // Execute business logic
        Item.Get(ItemNo);
        Item.CalcFields(Inventory);
        
        // Build response
        BuildInventoryResponse(Item, Argument);
    end;
}

Message Type Integration

Message type implementations use the setup to retrieve the correct interface:

Pattern: Message Type Implementation

codeunit 65323 "Item Availability Get Impl" implements "Cloud Event Msg Interface"
{
    internal procedure ExecuteCloudEventTask(var Argument: Record "Cloud Event Message Argument")
    var
        CloudEventsSetup: Record "Cloud Events Setup";
        AvailabilityInterface: Interface "Item Calc. Availability";
    begin
        // Validate specification version
        if Argument."Cloud Event Message Version" <> Argument."Cloud Event Message Version"::"1.0" then
            Error(UnsupportedVersionErr, Argument."Cloud Event Message Version");

        // Get the selected implementation from setup
        AvailabilityInterface := CloudEventsSetup.GetItemCalculateAvailabilityInterface();

        // Execute using the selected implementation
        AvailabilityInterface.CalculateAvailability(Argument);
    end;
}

This pattern ensures:


Extending the Setup

Adding a New Implementation

To add a new implementation:

  1. Create the Interface (if new feature area):
interface "My Custom Feature"
{
    procedure ProcessRequest(var Argument: Record "Cloud Event Message Argument")
}
  1. Create the Enum:
enum 50100 "My Custom Feature Type" implements "My Custom Feature"
{
    Extensible = true;
    
    value(0; "Default")
    {
        Caption = 'Default';
        Implementation = "My Custom Feature" = "My Default Impl";
    }
}
  1. Create the Implementation:
codeunit 50100 "My Default Impl" implements "My Custom Feature"
{
    procedure ProcessRequest(var Argument: Record "Cloud Event Message Argument")
    begin
        // Implementation logic
    end;
}
  1. Extend the Setup Table:
tableextension 50100 "My Setup Extension" extends "Cloud Events Setup"
{
    fields
    {
        field(50100; "My Custom Feature Type"; Enum "My Custom Feature Type")
        {
            Caption = 'My Custom Feature Type';
            DataClassification = CustomerContent;
        }
    }
}
  1. Add Setup Procedure:
tableextension 50100 "My Setup Extension" extends "Cloud Events Setup"
{
    procedure GetMyCustomFeatureInterface(): Interface "My Custom Feature"
    begin
        Rec.SetLoadFields("My Custom Feature Type");
        Rec.GetRecordOnce();
        exit("My Custom Feature Type");
    end;
}

Extending an Existing Enum

To add a new implementation to an existing feature:

enumextension 50101 "My Price Extension" extends "Item Price Calculation Type"
{
    value(50100; "External API")
    {
        Caption = 'External API Pricing';
        Implementation = "Item Price Calculation" = "My API Price Impl";
    }
}

codeunit 50101 "My API Price Impl" implements "Item Price Calculation"
{
    procedure CalculateItemPrice(var Argument: Record "Cloud Event Message Argument")
    begin
        // Call external API for pricing
        // Build response in standard format
    end;
}

Best Practices

1. Interface Design

2. Implementation Development

3. Enum Configuration

4. Setup Field Additions

5. Performance Optimization

6. Testing


Cloud Events Integration Log

Table: Cloud Events Integration (Table 65307) Page: Cloud Events Integration (Page 65314) Access: Cloud Events Setup → Messages → Cloud Events Integration

Purpose

The Cloud Events Integration log is an operational event log. Each record identifies:

The table uses a composite primary key of Source + Table Id + Date & Time, ensuring uniqueness per source-table-timestamp combination.

Fields

FieldTypeDescription
SourceText[250]External system or application identifier. Required (NotBlank).
Table IdIntegerID of the Business Central table involved.
Table NameText[30]Computed name of the table (FlowField). Read-only.
Date & TimeDateTimeTimestamp of the integration event. Required (NotBlank).
ReversedBooleanMarks a record as reversed (created by mistake).

API Access

Records in this table are read and written via the standard data message types:

``json { "tableName": "Cloud Events Integration" } ``

Retention Policy

The Cloud Events Integration table is registered with Business Central's retention policy framework. Administrators can configure automatic cleanup of old integration records via Administration → Data Management → Retention Policy.


Cloud Events Delete Log

Delete Setup

Table: Cloud Events Delete Setup (Table 65311) Page: Cloud Events Delete Setup (Page 65318) Access: Search → Cloud Events Delete Setup

The Delete Setup table controls which Business Central tables have their deletions captured to the delete log. Each row registers one table. When a record in that table is deleted, the extension logs the deletion automatically.

Fields

FieldTypeDescription
Table IdIntegerThe table to monitor. Required (NotBlank).
Table NameText[250]Resolved table caption (FlowField, read-only).
Store RecordBooleanWhen enabled, a full JSON snapshot of the record is saved at deletion time.

Caching Behaviour

Delete Setup records are cached in a SingleInstance codeunit (Cloud Events Delete Log Mgt, 65352) for performance. Any insert, modify, or delete on the setup table automatically resets the cache.

Delete Log

Table: Cloud Events Delete Log (Table 65309) Page: Cloud Events Delete Log (Page 65317) Access: Search → Cloud Events Delete Log

The Delete Log is a read-only audit trail. One entry is created per deleted record from any monitored table.

Fields

FieldTypeDescription
Entry No.IntegerAuto-increment primary key.
Table IdIntegerID of the table the deleted record belonged to.
Table NameText[250]Resolved table caption (FlowField, read-only).
Record System IdGuidThe SystemId of the deleted record.
Json DataBlobFull JSON snapshot (only populated when Delete Setup has Store Record enabled).
Deleted AtDateTimeTimestamp of the deletion.
User IDCode[50]The user who triggered the deletion.

Page Actions

Retention Policy

The Delete Log table is registered with Business Central's retention policy framework. Administrators can configure automatic cleanup via Administration → Data Management → Retention Policy, using the Deleted At field as the date reference.

API Access

Delete Log records can be retrieved via the standard data message types:


Cloud Events User Setup

Table: CE User Setup (Table 65318) Page: CE User Setup List (Page 65323) Card Page: CE User Setup Editor (Page 65322) Management Codeunit: CE User Setup Mgt (Codeunit 65440) Access: Search → Cloud Events User Setup (Usage Category: Administration)

Purpose

Per-user configuration for the Cloud Events extension. Each record stores a system prompt and optional linked-record overrides that are included in the Help.WhoAmI.Get response. The system prompt enables external AI systems to customise their behaviour per user. The optional link fields (resource, salesperson, employee, G/L account, customer, vendor, contact) override the default lookup logic so administrators can explicitly control which records appear in a user's profile.

Fields

FieldTypeDescription
User Security IDGuidPrimary key. Links to the User table.
User NameCode[50]Display name (FlowField from User).
System PromptBlobThe prompt text stored as UTF-8.
G/L Account No.Code[20]Optional. Links to a G/L Account for the dueFromToOwner section in Help.WhoAmI.Get.
Employee No.Code[20]Optional. Overrides the employee and manager sections in Help.WhoAmI.Get (skips Resource→Employee chain lookup).
Customer No.Code[20]Optional. Links to a Customer for the customer section in Help.WhoAmI.Get.
Vendor No.Code[20]Optional. Links to a Vendor for the vendor section in Help.WhoAmI.Get.
Resource No.Code[20]Optional. Overrides the resource section in Help.WhoAmI.Get (skips Time Sheet Owner lookup).
Salesperson CodeCode[20]Optional. Overrides the salesperson section in Help.WhoAmI.Get (skips User Setup lookup).
Contact No.Code[20]Optional. Links to a Contact for the contact section in Help.WhoAmI.Get.
Location CodeCode[10]Optional. Reserved for future use.

Security Model

The page uses a layered security approach:

  1. Auto-provisioning: On page open, EnsureCurrentUserExists() creates a record for the current user if one does not exist (uses InherentPermissions for RI access).
  2. Self-service editing: Users without full table permissions can only see and edit their own prompt (FilterGroup(2) applied). The UpdateOwnPrompt() procedure uses InherentPermissions for RM access.
  3. Admin editing: Users with full table data permissions (RMID) can see and edit all users' prompts.

Editor Behaviour

The User Setup Editor page provides a multi-line rich content field. On save, <div> tags are stripped via Regex before persisting to the blob.

Programmatic Access

var
    CEUserSetupMgt: Codeunit "CE User Setup Mgt";
begin
    CEUserSetupMgt.EnsureCurrentUserExists();
    CEUserSetupMgt.UpdateOwnPrompt('You are a helpful assistant.');
end;

Permission Sets

The Cloud Events extension ships several permission sets that gate access to specific features.

CE Approval Access

Permission Set ID: 65306 Name: CE Approval Access Assignable: Yes

Purpose: Controls which users may send documents to approval via the Document.Approval.Send message type. A user who does not hold this permission set receives an error response when calling Document.Approval.Send.

Error when missing:

User <UserSecurityId> does not have permissions to send documents to approval via Cloud Events.

How it works: The permission set grants write access to the gate table Cloud Events Approval Access (65314). The implementation checks WritePermission() on that table before processing the request — no records are stored in the table.

Assignment: Assign via the standard BC Permission Sets page or via user group.

CE Force Access

Purpose: Required to bypass the ChangeLog Write Guard when using "force": true in Data.Records.Set requests with the guard set to Via force. See ChangeLog Write Guard for details.

Posting Gates (CE G/L / Item / FA / Job / Resource / Warehouse Posting)

Every *.Post and *.Reverse message type that writes ledger entries is gated by a per-domain permission set. A user who does not hold the matching set receives an error response without any side effects:

Posting denied: missing 'CE <Domain> Posting' permission set.

The six permission sets are independent and **not bundled into CE Read or CE Full** — they must be granted explicitly. Each grants RIMD on an empty stub table (65323–65328) that BC's security kernel uses for the WritePermission() check; no records are ever stored.

Permission SetIDGate TableGated message types
CE G/L Posting65307Cloud Events G/L Posting (65323)Finance.GeneralJournal.Post, Finance.GeneralJournal.ReverseRegister, Finance.GeneralJournal.ReverseTransaction, Finance.BankReconciliation.Post, Finance.VAT.CalcAndPostSettlement, Customer.Application.Post, Customer.Application.Reverse, Vendor.Application.Post, Vendor.Application.Reverse, Sales.Document.Post, Purchase.Document.Post
CE Item Posting65308Cloud Events Item Posting (65324)Inventory.ItemJournal.Post, Inventory.TransferOrder.Post, Inventory.AssemblyOrder.Post
CE FA Posting65309Cloud Events FA Posting (65325)FixedAssets.FAJournal.Post
CE Job Posting65310Cloud Events Job Posting (65326)Projects.ProjectJournal.Post
CE Resource Posting65311Cloud Events Resource Posting (65327)Resources.ResourceJournal.Post
CE Warehouse Posting65312Cloud Events Warehouse Posting (65328)Warehouse.Shipment.Post (always; additionally requires CE G/L Posting when invoice = true)

Note: Sales.Document.Post and Purchase.Document.Post are gated to G/L only even though they may produce item and other ledger entries downstream. The gate represents the user's intent to trigger posting, not the entries that BC ultimately writes. Warehouse.Shipment.Post with invoice = true is the only operation that requires two permission sets simultaneously.

The check lives in codeunit Cloud Events Posting Gate (65600). To extend the model, add a new value to enum Cloud Events Posting Type (65324) and a matching gate table + permission set.


Related Documentation


Support

For questions regarding setup configuration or implementation development, please contact Origo support.


© Origo – Cloud Events Base Extension