After initialization is before initialization

2 minute read

Hello there 👋

Recently, I’ve come across a rarely used event called OnCompanyInitialize which is published by the Company-Initialize codeunit. In my case, I wanted to create a new evaluation company and found that some important configurations were missing in custom modules.

So whenever creating a new company, the event is triggered. This gives us the opportunity to initialize our modules with some pre-configurations for newly created companies.

Remember that the customer expects the extension to work the same way when creating additional companies as it did before.

Also notice that this is the recommended way by Microsoft: »If you are inserting data for a newly created company, we recommend subscribing to OnCompanyInitialize from Codeunit 2 instead.«1

Let’s take a look at an example:

codeunit 56780 "CB Install"
{
  Subtype = Install;

  trigger OnInstallAppPerCompany()
  begin
    ModuleInitialization();
  end;

  [EventSubscriber(ObjectType::Codeunit, Codeunit::"Company-Initialize", 'OnCompanyInitialize', '', false, false)]
  local procedure ModuleInitialization()
  var
      ModuleSetup: Record "Module Setup";
  begin
      if not ModuleSetup.Get() then begin
          ModuleSetup.Init();
          ModuleSetup.Insert();
      end;
  end;
}

This way you don’t have to worry about an uninitialized setup record. All the additional initialization steps are bundled into the CompanyInitialize procedure, which is triggered by the OnCompanyInitialize EventSubscriber.

There is also a CodeCop rule AA02352 that checks if the OnCompanyInitialize EventSubscriber is added. They also noticed that many extensions were missing an OnCompanyInitialize subscription3, which again goes back to my issue from the beginning. I found out about this rule from this tweet: https://twitter.com/rvanbekkum/status/1598703510794674176

UPDATE (2023-01-02) - A question was asked: “What’s the difference between the events OnAfterInitialization and OnCompanyInitialize?”. Good question.

Recently the OnAfterInitialization event became obsolete and is replaced by OnAfterLogin. That is because the OnAfterLogin shares an awesome new feature called Isolated Event4 which means that each subscriber is executed in its own transaction.

Now with that in mind, what’s the difference between this new event and the OnCompanyInitialize event? The answer hides inside the BaseApp codeunit CompanyInitialize. So, let’s take a look:

[EventSubscriber(ObjectType::Codeunit, Codeunit::"System Initialization", 'OnAfterLogin', '', false, false)]
local procedure CompanyInitializeOnAfterLogin()
var
    ClientTypeManagement: Codeunit "Client Type Management";
begin
    ...
    InitializeCompany();
end;

For a better overview I cut out a few lines. It’s just important to know that the InitializeCompany procedure is called at the end of the OnAfterLogin EventSubscriber.

This internal procedure now calls the OnRun trigger of the Company-Initialize codeunit:

internal procedure InitializeCompany()
var
    GLSetup: Record "General Ledger Setup";
begin
    if not GLSetup.Get() then
        CODEUNIT.Run(CODEUNIT::"Company-Initialize");
end;

So in the end, the OnCompanyInitialize event gets published after the setup procedures in the OnRun trigger (also cut out some lines for a better overview).

    trigger OnRun()
    begin
        Window.Open(Text000);

        OnBeforeOnRun();

        InitSetupTables();
        AddOnIntegrMgt.InitMfgSetup();
        InitSourceCodeSetup();
        ...

        OnCompanyInitialize();

        Window.Close();

        Commit();
    end;

With all this in mind, Isolated Event is a great improvement to the overall sustainability of the product. With a wide range of possible extensions from the marketplace5 to install, we want everything to run as stable as possible without affecting other non-dependent extensions. Otherwise, incidents may occure and users may not be able to sign-in again.

Hope you learned something new.

See you around 🦦