AL ID Range Manager (ALRM) for Business Central is available on Microsoft App Source!

I am super happy to announce that my solution for AL Language Developers for Business Central has just been certified by Microsoft and is available on Microsoft App Source for everyone for free!

If you have an account in the Business Central online, you can install the extension directly from Microsoft App Source. The other part of the extension (extension for VS Code) is also available on Microsoft VS Code Marketplace.

What is ALRM?

What is ALRM: AL ID Range Manager
– https://kepty.cz/2021/01/26/alrm-al-id-range-manager-introduction/

How to setup & use ALRM: AL ID Range Manager
– https://kepty.cz/2021/04/27/how-to-start-with-alrm-al-id-range-manager/

Source Codes

ALRM extension for VS Code and also for Business Central are open-source projects available under MIT license. You can find source codes on my GitHub.

Few words about the Microsoft App Source & ALRM

I have a big thank you to my partner’s company, ARTEX Informacni systemy spol. s r.o., Microsoft GOLD Partner for Small and Midmarket Cloud Solutions under whose partner’s account the extension is published on App Source. I successfully cooperate with this company for more than 6 years on many amazing projects in different industries and different countries. If you are looking for a strong and modern partner for your project, let me know and I will connect you with the best of best.

CU 2021/06 for Microsoft Dynamics NAV 2017 – 2018 and Microsoft Dynamics 365 Business Central on-premises has been released

The cumulative update 2021/06 for Microsoft Dynamics NAV 2017, NAV2018 and for Microsoft Dynamics 365 Business Central (2019 wave 1, 2020 wave 1, 2020 wave 2, 2021 wave 1) on-premises has just been released.

Support for older versions Microsoft Dynamics NAV 2016 and Microsoft Dynamics 365 Business Central 2019 wave 2 have ended with the last released Cumulative Update, so these versions are no longer mentioned in the table below.

VersionLinks
Microsoft Dynamics NAV 2017/CU54DownloadDocumentation
Microsoft Dynamics NAV 2018/CU41DownloadDocumentation
Microsoft Dynamics 365 Business Central Spring 2019 on-premises/CU24DownloadDocumentation
Microsoft Dynamics 365 Business Central 2020 Wave 1 on-premises/U16.13DownloadDocumentation
Microsoft Dynamics 365 Business Central 2020 Wave 2 on-premises/U17.7DownloadDocumentation
Microsoft Dynamics 365 Business Central 2021 Wave 1 on-premises/U18.2DownloadDocumentation

CU 2021/05 for Microsoft Dynamics 365 Business Central on-premises has been released

The cumulative update 2021/05 for Microsoft Dynamics 365 Business Central (2021 wave 1) on-premises has just been released.

This CU is officially a May release, even if it is released at the beginning of June. Microsoft announced earlier last month (see citation below) that the release will be delayed due to major refactoring of the BC on-premises installer.

We are implementing required refactoring of our installer for BC on-premises, specifically of pre-required components. This is unfortunately taking longer than anticipated. It’s our expectation that we can release Business Central on-premises version v18.1 by Friday, May 28, 2021.

Important re v10, 11, 14, 16, 17
We will not release the planned May updates but accumulate it all into June CU updates, utilizing May CU versions for June updates. This means that there will be no disruption in the numbering sequence but by end of this year you will only see us having released 11 CU updates.

by Lotte Cordt Ihlemann, Sr. Program Manager at Microsoft

As was announced, the only CU released is 18.1 (for Business Central 2021 wave 1). Other CUs for previous versions will be released in the near future as June CUs (alongside 18.2 that will be released a few days after 18.1).

VersionLinks
Microsoft Dynamics 365 Business Central 2021 Wave 1 on-premises/U18.1DownloadDocumentation

D365 Business Central database capacity changes valid from the 1st of July

On the Virtual Launch Event for Microsoft Dynamics 365 Business Central 2021 Release Wave 1, the major changes to the cloud-based version (Microsoft Dynamics 365 Business Central Online) have been introduced. The changes are not active yet; they will be effective from the 1st of July 2021.

The major problem for migrating from the On-Premise Business Central solution to the online version was the limitation (and price) of database capacity. No more with this change! Whats are the most interesting changes? Check the table below.

In the current situation, Business Central Online comes with 80 GB for your data with US$40 per GB over this limit. This was really, really expensive, and usually, it was a no-go for our projects. In that cases, the only way was to implement On-Premise.

With the new licensing, the price of database storage is changes drastically

  • 80 GB as a standard database capacity (no change)
  • You get
    • 2 GB per paid user if you use Essential licenses (currently 0 GB)
    • 3 GB per paid user if you use Premium licenses (currently 0 GB)

If you need a bigger database, Microsoft have also reduced price for additional space (all prices below are standard prices per month)

  • Per 1 GB, you will pay US$10 (currently US$40)
  • If you need more than 100 GB, you will pay US$5 per 1 GB, with a minimum of US$500 for the first 100 GB (currently US$40 per GB).

To remind the user pricing, the Essential license type (without manufacturing & service module) is US$70 per user. For the Premium license type, the price is US$100 per user.

To illustrate new pricing, imagine that you have an environment:

  • With 30 Essential Users, database size 50 GB
    • Now: 30 x US$70 per user = US$2100
    • From 01.07: 30 x 70 per user = US$2100
  • With 30 Essential Users, database size 100 GB
    • Now: 30 x 70 per user, 20 GB x US$40 = US$2900
    • From 01.07: 30 x 70 per user, 20 GB x US$10 = US$2300
  • With 30 Essential Users, database size 200 GB
    • Now: 30 x 70 per user, 120 GB x US$40 = US$6900
    • From 01.07: 30 x 70 per user, 120 GB x US$5 = US$2700

Are you looking for Business Central license?

If you are looking for a Business Central license for your company (cloud-based or an on-premise license version), do not hesitate to send me an email (kapitan@kepty.cz) with your questions or requirements. I have contacts on Microsoft Gold Partners in many countries who can help you with your project.

Forget Confirm() method; start with Confirm Management module

For a long time, if we wanted to get input from the user to confirm something, we used Confirm() method. This method is straightforward – it has two parameters (+ unlimited number of constant values similar to StrSubstNo() method). The first one accepts text shown to the user, the second one (optional) defines which button (OK/Cancel) is chosen as default.

 ...
 if Confirm('Confirm or Cancel?', true) then
   Message('Confirmed')
 else
   Message('Canceled');
 ...

The biggest issue with this design is that every time we use this method, we have to think about the process as a whole – whether a user action will call the method or whether it will also be called from the system (job queue, APIs, …) process. In that case, we have to think about how the confirmation dialogue should behave during the process with no user input and suppress the dialogue using GuiAllowed() method.

“Confirm Management” module

Confirm management is a new module (it is not really so new; it is available since the first versions of the Business Central). The source of the module is available on Microsoft GitHub.

The module contains two methods GetResponse and GetResponseOrDefault. The difference is what the method returns if Gui is not allowed.


 codeunit 27 "Confirm Management"
 {
   procedure GetResponseOrDefault(ConfirmQuestion: Text; DefaultButton: Boolean): Boolean
   begin
     if not IsGuiAllowed() then
       exit(DefaultButton);
     exit(Confirm(ConfirmQuestion, DefaultButton));
   end;

   procedure GetResponse(ConfirmQuestion: Text; DefaultButton: Boolean): Boolean
   begin
     if not IsGuiAllowed() then
       exit(false);
     exit(Confirm(ConfirmQuestion, DefaultButton));
   end;

   ..
 }

In that case, GetResponse() always returns false in comparison to GetResponseOrDefault() that returns the default value passed to the method as one of the parameters.

What’s more, there is also the publisher method OnBeforeGuiAllowed() that we can use to manage whether the Gui is allowed or not. It can be used, for example, to simulate job queue runs called directly by the user (admin).

Returning complex types in AL Language

In Microsoft Dynamics 365 Business Central 2021 w1 (released in May 2021), a profound change was introduced to ways how we can design our applications

Until this version, the only way to return complex data types (like records, codeunits, Lists etc.) was using the var parameter (see example below).


 trigger OnRun()
 var
   SalesHeader: Record "Sales Header";
 begin
   FindSalesOrder('SO210001', SalesHeader);
   SalesHeader.TestStatusOpen();
 end;

 local procedure FindSalesOrder(OrderNo: Code[20]; var SalesHeader: Record "Sales Header")
 begin
   Clear(SalesHeader);
   SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order);
   SalesHeader.SetRange("No.", OrderNo);
   SalesHeader.FindFirst();
 end;

Although it allows returning any data type, working with var parameters is not as friendly as working with return parameters. For example, var parameters do not allow method chaining.

It was not possible in C/AL or AL Language. Until now!


 trigger OnRun()
 var
   SalesHeader: Record "Sales Header";
 begin
   FindSalesOrder('SO210001').TestStatusOpen();
 end;

 local procedure FindSalesOrder(OrderNo: Code[20]) SalesHeader: Record "Sales Header"
 begin
   Clear(SalesHeader);
   SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order);
   SalesHeader.SetRange("No.", OrderNo);
   SalesHeader.FindFirst();
 end;

With returning of complex types, we can chain methods similarly to C# (or any other modern object-oriented language) with returning of complex types.


 // With var parameter
 FindSalesOrder('SO210001', SalesHeader);
 SalesHeader.TestStatusOpen();

 // With returning complex types
 FindSalesOrder('SO210001').TestStatusOpen();

What is/isn’t possible to return

It is possible to return almost any data type.

  • Any simple type
    • Boolean, Integer, Text, Char, …
    • RecordRef, FieldRef, Variant
  • Any AL object
    • Records (Record “Sales Header”)
    • Pages (Page “Customer Card”)
    • Codeunits (Codeunit “Sales-Post”)
  • Selected DotNet objects
    • HttpClient, HttpContent, …
  • Other complex types
    • Lists (List of [Text])
    • Dictionaries (Dictionary of [Integer, Text])

The only things that are not possible to return are collections of complex types (something like List of [Records “Sales Header”]). However, it is not a limitation of return statements, but it is impossible to use collections of complex type in AL Language in general.

For this purpose, use Temporary Records instead.

Let’s chain it!

So how we can advance from method chaining in AL Language?

For example, imagine you want to work with data from the customer card for a customer from the sales header. Without chaining, the only way was to create a Customer variable and find the corresponding customer manually or using var parameter using the method in the Sales Header.

With chaining, we can use the getter method in the Sales Header that returns the customer (unfortunately, there isn’t the method yet). See the example below.

Example

Unfortunately, there aren’t any useful function in the base app yet, so the example uses methods as if they were in the base app.

I added a method procedure GetCustomer(): Record Customer to the Sales Header table and procedure GetShipToAddress(ShipToAddressCode: Code[10]): Record “Ship-to Address” to the Customer table.


 // Method in Sales Header table
 procedure GetCustomer(): Record Customer
 var
   Customer: Record Customer;
 begin
   Customer.Get(Rec."Sell-to Customer No.");
   exit(Customer);
 end;

 // Method in Customer table
 procedure GetShipToAddress(ShipToAddressCode: Code[10]): Record "Ship-to Address"
 var
   ShipToAddress: Record "Ship-to Address";
 begin
   ShipToAddress.Get(Rec."No.", ShipToAddressCode);
   exit(ShipToAddress);
 end;

Now we can get values (in our example, the value of email field) from Ship-to Address only with one line of custom code.


 procedure DoSomething(SalesHeader: Record "Sales Header")
 var
   EmailFromShipToAddressTable: Text[80];
 begin
   EmailFromShipToAddressTable := SalesHeader.GetCustomer().GetShipToAddress('ADDR-001')."E-Mail";
   Message(EmailFromShipToAddressTable);
 end;