Tip & Tricks

Migration from BC-14 (On-Prem) to BC-21 (SAAS)

AL, BC14, BC15, BC16, BC17, BC18, Business Central, C/AL, Cumulative Updates, Dynamics 365, End of Mainstream, Extension, Information, NAV 2015, NAV 2016, NAV 2017, NAV 2018, Navision, on-premises, Online, Updates, upgrade

Comparison of BUSINESS CENTRAL AND NAV

First released in 1987, acquired by Microsoft in 2002, now called Business Central, Dynamics NAV is one of Microsoft’s most prolific software packages. 

After Dynamics NAV 2018, Microsoft discontinued their popular, but on-premises only, ERP solution Dynamics NAV and replaced it with Dynamics 365 Business Central (BC-13). But what is the difference between the two systems, and why should your business make the switch? Let’s take a look at Business Central vs Dynamics NAV.

Microsoft Dynamics NAV was rebranded in 2018 to Microsoft Dynamics Business Central for on-premises and private cloud versions, and Microsoft Dynamics 365 Business Central for the cloud version.

At the time of writing this comparison, BC-21 is available in market.

Since 2018, Dynamics NAV is no longer available for purchase. The only businesses that can use the system are those that already held licenses. Even for those who do still hold licenses, the system no longer receives updates, meaning the software will quickly become outdated and harder to use.

Mainstream Support for Dynamics NAV versions from 2013 to 2017 has already ended, with the 2018 version losing support in January 2023. This deadline is fast approaching, so if you are currently using NAV 2018 you should begin to consider your optimal course of action going forward.

With very little time remaining before the end of Dynamics NAV Mainstream Support in January 2023, the sooner you decide on your course of action, the better.

Microsoft introduced Dynamics 365 Business Central. Business Central is a newer version of Dynamics NAV, offering the same standard functionality in a much more user-friendly way. It’s also SaaS (Software as a Service) meaning it’s accessible from anywhere, with the same security that drives Microsoft 365.

In addition to the functions carried over from Dynamics NAV, the Dynamics 365 Business Central system affords users with access to:

  • Integration with Microsoft 365 applications for increased productivity and streamlined data
  • Data connectivity and business intelligence through Microsoft Power Platform
  • Microsoft Azure architecture for cloud security, presence, and scale
  • Increased pool of third-party software integrations
  • Multiple deployment options for on-premises, private server, or cloud hosting

Microsoft Dynamics 365 Business Central helps with day-to-day business processes and operations. Its capabilities include financials, stock management, purchasing and much more, all with real-time data and analytics through Power BI.

Dynamics 365 Business Central is relevant for businesses adopting flexible, hybrid, or remote working models thanks to the scalable, cloud-based architecture and integration with Microsoft 365 and Power BI tools.

It is an all-in-one solution that can be adapted for many industries including software developers, IT services, financial services, healthcare, and educational institutions.

The system also has large user bases in manufacturing, distribution, ecommerce, and retail. 

Features and functions are still the same as back in the NAV days, just with a more digital-focused platform. But still differ from old days Dynamics NAV.

Most of the base code of Business Central has been adapted from NAV, and it has enhanced the rich functionality its predecessor offered, with options to deploy as an on-premises or a SaaS cloud solution.

The Dynamics 365 Business Central web client, including its sisters, the tablet and phone clients (by the way, there is no longer a Windows client) has had a makeover!

Features include new and varied fonts to highlight important information such as a headline banner on the Role Centre, a fabulous teal Role Centre with easy navigation, and interestingly capitalised field names on lists!

They are curiously small differences but really nice touches.

Design Tool it’s as good as it used to be! In fact, it’s a very smart design tool. As a ‘non-developer’ you can amend pages, add new fields and save the result as an extension.

When comparing Dynamics NAV to Business Central, you must be aware of the substantial functional upgrades and new capabilities of Dynamics 365 Business Central. Microsoft Dynamics 365 Business Central is an upgrade to Microsoft Dynamics NAV that offers several notable improvements.

You’ll see numerous benefits in your business, including agility, ability to scale quickly, mobility, lower cost of ownership, and more.

Microsoft Dynamics NAV and Microsoft Dynamics 365 Business Central have many similarities, but there are many differences too that make many users move from NAV to Business Central.

You can also choose to deploy Business Central as an on-premises solution if that is a better fit for your organization. However, you may then miss out on integration and cutting-edge features.

While the two systems are similar, there are key differences that make Business Central the preferred option for many businesses:

Business CentralDynamics Navision
 Dynamics 365 Business Central is a cloud-based ERP solution.  

With Dynamics 365 Business Central, you can access your data and applications anytime, anywhere, and on any device.  

D365 Business Central includes a comprehensive set of features and functionality.  

Business Central is licensed on a per-user basis.  

With Business Central, you only need to pay for the users who will be using the system.
Dynamics NAV is an on-premises ERP solution.  

Dynamics NAV requires some customization and third-party add-ons to achieve the same level of functionality.  

Dynamics NAV is licensed on a per-server basis.  

Dynamics NAV, you need to pay for the server regardless of how many users are accessing the system.
IntegrationFull (All Microsoft Products)Limited, Version Dependent 
Objects49,999 objects are free to use on cloudObjects need to be purchased for customizations 
Search Interface Advanced, with automatic categorization, smart search (search for misspellings or imprecise terms) Basic, possibility of data duplication 
Reporting Power BI Limited 
Deployment Cloud (No need to maintain servers and backups) although On-Premises option also available.On-Premises, Cost for Server maintenance and backup management.
USER INTERFACEWeb-based app
Improved design
Much easier to navigate.
More productive platform.
Desktop-based 
 Business Central interface uses AL language in the code.  

Offers more customization than before and helps to make extensions and upgrades much easier to manage in the long term.
Dynamics NAV using C/AL coding
 Better integration with other Microsoft products already used by many businesses, including all applications within the Microsoft Dynamics suite, like Microsoft Dynamics 365 Sales (CRM) and Office 365 products, such as Outlook and Excel. 
 Offers more automated operations to improve productivity.  

Native connectivity to Microsoft’s Power Platform (e.g., Power Automate) and powerful workflows and integrations can be created, by end-users without complex coding, sometimes almost no code.
 
HOSTINGBusiness Central is a SaaS solution – sitting on Microsoft’s Azure cloud, which enables you to specify the region where your data is stored and processed.  

There are many benefits to SaaS solutions,

*  Greater security
* Less risk of data loss and
* Better accessibility for your team.
* Cloud hosting also works alongside the new coding to make upgrades and extensions much easier to carry out.
Only On-Premises capability.

Need to invest in and manage your own in-house servers.
UPGRADESBi-annual release
Sequential upgrades,
Which happen automatically.
Your systems are always up to date.  

With the on-premises or private cloud version of Business Central, upgrades are not automatic but are still relatively simpler compared to NAV.  

Plus, any third-party apps or customizations you have are also designed to be compatible with each new Business Central update.
No Automatic Upgrades.
 Your business is always using the most optimised version of Business Central.Fuss and cost of manually updating the software.
 If you are apprehensive about an update, there is an option to delay its installation for up to 90 days.

However, it’s good idea to staying as up to date as possible. Updates are introduced to improve overall user experience and security.
Hotfixes & Cumulative updates to be handled on own cost.
 Business Central, the modifications are made using AL language that creates extensions – leaving the core system untouched and making upgrades a lot easier.NAV customization was written in C/AL language and was integral to the core system.

This meant upgrades were a major undertaking as the whole system needed to be reviewed and potentially redeveloped.
USER LICENSESDynamics 365 Business Central uses a monthly/annual subscription model and is available in either (‘Essentials’ or ‘Premium’).  

Charges per user, meaning fees are based on the number of simultaneous users each month.  

You also get an option to pay a perpetual license fee. That means you can now Business Central as an operational expense or a capital expense, whichever makes more sense for your business. It also moves from a concurrent user to a named user licensing model.
Perpetual with yearly AMC 16% in license cost.  

Dynamics NAV is available in Starter Pack & Extended Pack.
 Business Central users can also benefit from Single Sign On and usability across multiple devices, and across iOS, Android, and PC. 
 Remote working much easier, especially as the landscape of working life is becoming a blend of office-based and home working.  

Flexible and cost-effective for businesses.
 
 Now your staff can simply log into the web app from any device to get their job done. This makes the ERP solution much more cost-effective and flexible for your business. 

HOW TO TRANSITION TO BUSINESS CENTRAL

Many companies have been using Dynamics NAV for years, so Nav users may be a little wary about making the switch to Business Central. But with even more functionality than the NAV solution and with better usability, you won’t regret taking the first step.

While some Microsoft products, like Office 365, can be bought directly from Microsoft, this is not the case for Business Central. Due to the complexity of the product, Microsoft Business Central must be purchased through an approved Microsoft partner.

The Business Central trial takes a few minutes to load, and you can start using the app. 

Dynamics 365 Business Central Licensing

There are two main subscription licensing options:

  • Business Central Essentials
  • Business Central Premium.

To use this ERP software, you must license one of these plans. Both plans are licensed by user and are fast to implement as well as easy to configure. There’s also a ‘Team Members‘ licensing option to add on additional users.

The difference between a full user vs. an additional user:

A full user is someone who will be working heavily within Business Central on a daily basis. These will typically be your customer service employees, sales and marketing staff, finance employees, and supply chain managers.

An additional user or team member is a ‘light user’ or users who do not require the full capabilities of Business Central. For instance, they may need to view data reports, log their expenses or time, and other such activities.

Dynamics 365 Business Central Essentials

Microsoft Dynamics 365 Business Central Essentials consists of several modules that are considered essential for any business.

Modules included within Essentials:

  • Financial Management
  • Supply Chain Management
  • Customer Relationship Management
  • Project Management
  • Warehouse Management
  • Human Resources Management

Dynamics 365 Business Central Premium

The Premium license has everything in the Essentials license plus service management and manufacturing.

Modules included within Premium:

  • Service Management
  • Manufacturing
  • Financial Management
  • Supply Chain Management
  • Customer Relationship Management
  • Project Management
  • Warehouse Management
  • Human Resources Management

Authorization, Base64 Convert, Business Central, InStream, Integration, JSON, JsonObject, JsonToken, OData, Post, Postman, SOAP, Tenant Media, Tip & Tricks, URL, Web Access Key, Web Services

Integrating with Business Central – using Web Service

This is fourth post in this series, if you wish to see first post, you can access here.

In second post I discussed about, how to create Azure Functions, you can access here.

In previous post I discussed about, how to Integrate Azure Functions in Business Central, you can access here.

In this post we will discuss how to make available QR Image using API by exposing as Web Service.

Let’s cut the theoretical part and coming directly to the solution.

This post is very short and as an answer to query from one of the blog readers, who regularly gives feedback and suggest topic he wish from me. Sometime it is not possible to write post for every query, but I try to pick some which I find interesting. Converting any topic into post is quite time taking, solution can be of 10 mins but presenting same in form of blog takes 2-3 hours, sometimes even more.

Some time appropriate environment is not available where I can put the solution and take screenshots to present as blog.

Since this topic is part of current series, I am writing posts on, so I was able to easily pick this topic.

Requirement is to add capability to get QR Image we generated in our previous posts using Web Service/ API/ OData/ JSON Base64Text.

To get this working we will first create a Codeunit with appropriate methods and expose it as Web Service.

Step – 1.

Create Codeunit & Add below method.

Step – 2

Publish above Codeunit as Web Service.

Step – 3

Copy SOAP URL

[SOAP URL]

https://api.businesscentral.dynamics.com/v2.0/1e4fc386-962e-4a20-8364-d5aeb65e2485/Test/WS/CRONUS%20USA%2C%20Inc./Codeunit/QRCodeGenerator

Convert to ODataV4 URL by making necessary modification as below:

[ODataV4 URL]

https://api.businesscentral.dynamics.com/v2.0/1e4fc386-962e-4a20-8364-d5aeb65e2485/Test/ODataV4/QRCodeGenerator

Similarly, your $metadata URL will be:

https://api.businesscentral.dynamics.com/v2.0/1e4fc386-962e-4a20-8364-d5aeb65e2485/Test/ODataV4/$metadata

Run the metadata URL in browser:

Search for your function created above, you should get definition as below:

<Action Name=”QRCodeGenerator_GetQRSetImageAsJSON”>

<Parameter Name=”qRSetId” Type=”Edm.Int32″/>

<ReturnType Type=”Edm.String”/>

</Action>

Let’s test the above URL for function using Postman to see the result:

[POST] – https://api.businesscentral.dynamics.com/v2.0/1e4fc386-962e-4a20-8364-d5aeb65e2485/Test/ODataV4/QRCodeGenerator_GetQRSetImageAsJSON?Company=CRONUS USA, Inc.

Authorization:  Basic Auth

Username: ASHWINI.TRIPATHI

Password: xjAtAtTaFhgXkgR4M5WoHapotvJNmqJ5//XBYK2v5s4= (Web Service Access Key)

JSON Parameter to Function: (Body raw:JSON)

{

    “qRSetId” : “6”

}

Result Body:

{

    “@odata.context”: “https://api.businesscentral.dynamics.com/v2.0/1e4fc386-962e-4a20-8364-d5aeb65e2485/Test/ODataV4/$metadata#Edm.String&#8221;,

    “value”: “iVBORw0KGgoAAAANSUhEUgAAApQAAAKUAQMAAACAATp/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAGUExURQAAAP///6XZn90AAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHtSURBVHja7dpbasMwEAXQ2YH3v0vvwKVBsZ44DZ4UWs58BEnMHH1eYjuO9NqZTCaTyWQymUwmk8lkMplMJpPJZDKZ/8KMsbb27Ls3St+2bmYymUwmM8Ws58N2b+FiXjQzmUwmk3nTLMN1qkPq6LqZyWQymczPmUdTwxVMJpPJZP6G+di0/7lqH5PJZDKZnzOnK7ZzW2tbNzOZTCaTmWIOtbXw9DM3M5lMJpOZYK6rPvSL9huJywkmk8lkMu+Yz0d9tR7HQ7INl9UWJpPJZDITzDIwv39arVbNTCaTyWRmmS0XbZ5Nq64uM47JZDKZzDfMdmrv4W47ZByTyWQymalm7S2rre0tq+eNxRw4JpPJZDITzDhjq8uu9p5udSLBZDKZTGae+UyxKd4GqWbc3MxkMplMZpZ5EXSdVPuYTCaTyUw12/kh1Dq4rVcZx2QymUzmG+aqinmcU12etdceTCaTyWSmmDHWkHaDNJ8xmUwmk5li1vM6GjFfu60nmEwmk8nMMuvUFGV7zPWjjGMymUwm87ZZt/Pqcc/wXJDJZDKZzE+apSXOV1TRf9HHZDKZTGaiub4i+ijb+48iDiaTyWQyM82h2rZYRFmsYpDJZDKZzHtmVjGZTCaTyWQymUwmk8lkMplMJpPJZDL/rHnsXwW1n/zFqtyZAAAAAElFTkSuQmCC”

}

Copy the Value and use any base64 – image converter tool, search on Google

You will get your QR Image:

Don’t try any URL or Passwords in this post as same is modified, and in images covered to hide actual url & passwords.

Hope you enjoyed learning from this post.

That’s all for this post, but visit again to learn from upcoming posts in this series, will post soon.

See you again in next post, till then keep exploring, learning and sharing with others.

Azure Functions, Business Central, Integration, QR Code, Tip & Tricks

Integrating Azure Function with Business Central

This is third post in this series, if you wish to see first post, you can access here.

In previous post I discussed about first part, how to create Azure Functions, you can access here.

Today in this post I will discuss about second part, how to Integrate previously created Azure Functions in Business Central.

From previous post remember:

On completion you will get the Live AZURE URL, use the URL in same way as for local, to pass parameter append at the end of URL as (?ReqData=Test)

Replace [Test] with the information for which you want to generate the QR Code.

Let’s start with Business Central side customization required, here I am presenting partial design for learning purpose, if you need full functional setup-based configuration for generating QR Code integrated with your system, I have the solution ready, you can connect with me for complete solution for your business. Actual solution has much more capability than what is presented here.

First, we will design a table to store all generated QR Code & assign an QR Set Id, which you can add in your other tables, just like Dim Set Id.

Only bare minimum code is included just to give idea about how we can integrate Azure Functions to Generate QR Code in Business Central.

Next, we will design page for this table.

Next, we will design page to display QR Set Image generated for QR Code Data.

QR Code Data is text created with information for which QR Code need to be generated.

Next, we will create a function which will generate QR Image using Azure function we created in previous post.

You can create a codeunit and add your function to generate QR Code Image as above. Replace Url with exact you obtained in previous post after deploying your function.

You need to write one more function which create a new record in your table and populate QR Code Data value with the information you wish to generate QR Image for.

Once your QR Code Set Record is ready call this function to Generate QR Code Image for you, based on information you created in QR Code Data.

For Example, add this procedure to any table where you wish to Generate QR Code.

You need to implement your logic for generating QR Code Data, for example you wish to Generate QR Code for Item with information like [ItemNo|Description]

You can populate QR Code data as:

QRSet.”QR Code Data” := Rec.”No.” + ‘|’ + Rec.Description;

Don’t forget to add one field to this table as “QRSet Id” and assign the “QRSet Id” as QRSet.”QR Code Set Id” in above procedure GenerateQRCode after QRSet is Inserted.

Your QR Image will be generated with this information, when you scan you QR Image you will get information that you passed as parameter to “QR Code Data”.

Similarly, you can add below actions to your respective page for above table:

Now build and publish your extension.

Open the page where you added the Action, first call Generate QR Code, this will populate the QR Code Set with the information as per your logic, Get the QR Image from the Azure function and save it into your table QR Code Set. Next you call View QR Code, this will fetch the QR Image from the table and display on screen.

Hope you enjoyed learning from this post.

That’s all for this post, but visit again to learn from upcoming posts in this series, will post soon.

See you again in next post, till then keep exploring, learning and sharing with others.

Business Central, Dataverse, Dynamics 365 Sales, Integration, Synchronize, Testing, Tip & Tricks

Test the Solution Integration of Business Central with Dataverse

This is the Twelfth post in the series. If you want to go to previous post click here.

From the series of steps this post is dedicated to Step-Testing:

As a Eleventh Step we will Verify & Test the Integration between Business Central and Dataverse for Custom table we created in both the environments.

Initial Stage post Deploying the Extension, we access the Pages for first time.

We have below data in Dataverse Prospects table:

In BC when we access to CDS Prospects Page:

In BC when we access to Prospects Page:

First we will Add one Record in Dataverse:

Now if we check CDS Prospects Page:

If you remember on CDS Prospects Page we have written code on OnInit trigger to run codeunit – CRM Integration Management, so when page is opened, the data is synchronized to CDS Prospects Page.

On CDS Prospects Page, we have also added action Create in Business Central, if we choose this action:

The record in Dataverse will get transferred to Prospect Table in Business Central

Now Let us Add one Record in Business Central, from Prospect Page.

Business logic for calculating Forcast Revenue is not written in BC, but we have in Dataverse table.

When we synchronize data from BC to Dataverse, that will get calculated automatically.

Select the record we just added in BC. Action-> Dataverse-> Coupling-> Setup Coupling

On the new page that opens, Select Create New, And click OK.

Since we have selected Synchronize After Coupling and direction BC to Dataverse, the record will get transferred to Dataverse Table.

Also you can see the other fields too got calculated. Now if we Synchronize back to BC these fields will get updated in BC.

You can see the Synchronization is happening in both directions.

You can make necessary changes to code in sample walkthrough to achieve your desired results.

Hope you enjoyed learning this trick, and will use in your projects, the skill learned from this series of posts.

I will come up with more similar stuffs. Till then keep exploring, learning and sharing with others.

Take care of yourself and your loved ones. Put your mask, maintain safe distance and don’t forget to get vaccinated.

Business Central, Business Central Dataverse Integration, Business Central Integration Business Central to Common Data Service, Dataverse, Dynamics 365 Sales, Integration, Organization, Permission, Power Apps, Roles, Security, Synchronize

Check & Assign Permissions in Power Apps Environment

This is the Eleventh post in the series. If you want to go to previous post click here.

From the series of steps this post is dedicated to Step-10:

As a Tenth Step we will Verify & Assign Permissions in Power Apps Environment.

This is the final Step, and we will be done with the goal we set in our first post of this series.

Open your Dynamics 365 Sales Environment and Go To Settings.

Under Users + permissions -> Application users.

On next screen Verify “Business Central Integration Business Central to Common Data Service” is selected. If not then select it from “Edit Security Roles”.

From Settings -> Users + permissions -> Security roles

From Security roles select the Business Central Dataverse Integration Then Edit

Select Custom Entities tab and find your table Prospects. Select each circle 4 times to assign Organization, circle should turn completely filled green color.

Select Save and Close.

Now you All done with the steps, Ready to test the solution.

In next post we will test the solution, we created in past 10 posts.

Now you are good to proceed with Next Step.

You can jump to Next Step from here.

Business Central, Dataverse, Dataverse Connection Setup, Dynamics 365 Connection Setup, Fields, Integration, Mappings, Setup, Synchronize

Updating the default Mappings

This is the Tenth post in the series. If you want to go to previous post click here.

From the series of steps this post is dedicated to Step-9:

As a Nineth Step we will Update the default Mappings.

Open the Dataverse Connection Setup using TellMe.

From Actions -> Use Default Synchronization Setup.

Respond Yes to the Confirmation Message.

You will get the confirmation as completed, say OK to continue.

Next open the Microsoft Dynamics 365 Connection Setup from TellMe.

Go To Mapping -> Integration Mappings.

Now you can find your Custom table Prospects.

Go To Fields, you will see Field Mappings for you table as defined in Integration Codeunit in previous step.

Now you are good to proceed with Next Step.

You can jump to Next Step from here.

AL, Business Central, Codeunit, Dataverse, Events, Extension, Integration, Procedures, Subscription, VS Code

Create Integration Codeunit for Business Central & Dataverse Integration

This is the Seventh post in the series. If you want to go to previous post click here.

From the series of steps this post is dedicated to Step-6:

As a Sixth Step we will Create Integration Codeunit in Business Central

codeunit 50120 CDSDataverseEvent
{
}

Add these Procedures

local procedure LookupCDSProspect(SavedCRMId: Guid; var CRMId: Guid; IntTableFilter: Text): Boolean
    var
        CDSProspect: Record "CDS cr95d_Prospects";
        OriginalCDSProspect: Record "CDS cr95d_Prospects";
        OriginalCDSProspectList: Page "CDS Prospect List";
    begin
        if not IsNullGuid(CRMId) then begin
            if CDSProspect.Get(CRMId) then
                OriginalCDSProspectList.SetRecord(CDSProspect);
            if not IsNullGuid(SavedCRMId) then
                if OriginalCDSProspect.Get(SavedCRMId) then
                    OriginalCDSProspectList.SetCurrentlyCoupledCDSProspect(OriginalCDSProspect);
        end;

        CDSProspect.SetView(IntTableFilter);
        OriginalCDSProspectList.SetTableView(CDSProspect);
        OriginalCDSProspectList.LookupMode(true);
        if OriginalCDSProspectList.RunModal = ACTION::LookupOK then begin
            OriginalCDSProspectList.GetRecord(CDSProspect);
            CRMId := CDSProspect.cr95d_ProspectsId;
            exit(true);
        end;
        exit(false);
    end;

local procedure AddEntityTableMapping(CRMEntityTypeName: Text; TableID: Integer; var TempNameValueBuffer: Record "Name/Value Buffer" temporary)
    begin
        TempNameValueBuffer.Init();
        TempNameValueBuffer.ID := TempNameValueBuffer.Count + 1;
        TempNameValueBuffer.Name := CopyStr(CRMEntityTypeName, 1, MaxStrLen(TempNameValueBuffer.Name));
        TempNameValueBuffer.Value := Format(TableID);
        TempNameValueBuffer.Insert();
    end;

local procedure InsertIntegrationTableMapping(var IntegrationTableMapping: Record "Integration Table Mapping"; MappingName: Code[20]; TableNo: Integer; IntegrationTableNo: Integer; IntegrationTableUIDFieldNo: Integer; IntegrationTableModifiedFieldNo: Integer; TableConfigTemplateCode: Code[10]; IntegrationTableConfigTemplateCode: Code[10]; SynchOnlyCoupledRecords: Boolean)
    begin
        IntegrationTableMapping.CreateRecord(MappingName, TableNo, IntegrationTableNo, IntegrationTableUIDFieldNo, IntegrationTableModifiedFieldNo, TableConfigTemplateCode, IntegrationTableConfigTemplateCode, SynchOnlyCoupledRecords, IntegrationTableMapping.Direction::Bidirectional, 'CDS');
    end;

procedure InsertIntegrationFieldMapping(IntegrationTableMappingName: Code[20]; TableFieldNo: Integer; IntegrationTableFieldNo: Integer; SynchDirection: Option; ConstValue: Text; ValidateField: Boolean; ValidateIntegrationTableField: Boolean)
    var
        IntegrationFieldMapping: Record "Integration Field Mapping";
    begin
        IntegrationFieldMapping.CreateRecord(IntegrationTableMappingName, TableFieldNo, IntegrationTableFieldNo, SynchDirection,
            ConstValue, ValidateField, ValidateIntegrationTableField);
    end;

To Add Event Subscriptions, Use the new Shift+Alt+E shortcut in the AL code editor to invoke a list of all events.

Search for Event OnGetCDSTableNo“CRM Setup Defaults”

[EventSubscriber(ObjectType::Codeunit, Codeunit::"CRM Setup Defaults", 'OnGetCDSTableNo', '', false, false)]

local procedure OnGetCDSTableNo(BCTableNo: Integer; var CDSTableNo: Integer; var handled: Boolean);
    begin
        if BCTableNo = DATABASE::"Prospect" then begin
            CDSTableNo := DATABASE::"CDS cr95d_Prospects";
            handled := true;
        end;
    end;

Search for Event OnLookupCRMTables“Lookup CRM Tables”

[EventSubscriber(ObjectType::Codeunit, Codeunit::"Lookup CRM Tables", 'OnLookupCRMTables', '', false, false)]

local procedure OnLookupCRMTables(CRMTableID: Integer; NAVTableId: Integer; SavedCRMId: Guid; var CRMId: Guid; IntTableFilter: Text; var Handled: Boolean);
    begin
        if CRMTableID = Database::"CDS cr95d_Prospects" then
            Handled := LookupCDSProspect(SavedCRMId, CRMId, IntTableFilter);
    end;

Search for Event OnAddEntityTableMapping“CRM Setup Defaults”

[EventSubscriber(ObjectType::Codeunit, Codeunit::"CRM Setup Defaults", 'OnAddEntityTableMapping', '', false, false)]

local procedure OnAddEntityTableMapping(var TempNameValueBuffer: Record "Name/Value Buffer");
    begin
        AddEntityTableMapping('Prospect', DATABASE::"CDS cr95d_Prospects", TempNameValueBuffer);
    end;

Search for Event OnAfterResetConfiguration “CDS Setup Defaults”

[EventSubscriber(ObjectType::Codeunit, Codeunit::"CDS Setup Defaults", 'OnAfterResetConfiguration', '', false, false)]

local procedure OnAfterResetConfiguration(CDSConnectionSetup: Record "CDS Connection Setup");
    var
        IntegrationTableMapping: Record "Integration Table Mapping";
        IntegrationFieldMapping: Record "Integration Field Mapping";
        CDSProspect: Record "CDS cr95d_Prospects";
        Prospect: Record "Prospect";
    begin
        InsertIntegrationTableMapping(
            IntegrationTableMapping, 'Prospect',
            DATABASE::"Prospect", DATABASE::"CDS cr95d_Prospects", CDSProspect.FieldNo(cr95d_ProspectsId), CDSProspect.FieldNo(ModifiedOn), '', '', true);

        InsertIntegrationFieldMapping('Prospect', Prospect.FieldNo("No."), CDSProspect.FieldNo(cr95d_ProspectsId), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);

        InsertIntegrationFieldMapping('Prospect', Prospect.FieldNo(Name), CDSProspect.FieldNo(cr95d_ProspectName), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);

        InsertIntegrationFieldMapping('Prospect', Prospect.FieldNo(Probability), CDSProspect.FieldNo(cr95d_Probability), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);

        InsertIntegrationFieldMapping('Prospect', Prospect.FieldNo("Contract Amount"), CDSProspect.FieldNo(cr95d_ContractAmount), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);

        InsertIntegrationFieldMapping('Prospect', Prospect.FieldNo("Contract Amount (Base)"), CDSProspect.FieldNo(cr95d_contractamount_Base), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);

        InsertIntegrationFieldMapping('Prospect', Prospect.FieldNo(Stage), CDSProspect.FieldNo(cr95d_Stage), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);

        InsertIntegrationFieldMapping('Prospect', Prospect.FieldNo("Forecast Revenue"), CDSProspect.FieldNo(cr95d_ForcastedRevenue), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);

        InsertIntegrationFieldMapping('Prospect', Prospect.FieldNo("Forecast Revenue (Base)"), CDSProspect.FieldNo(cr95d_forcastedrevenue_Base), IntegrationFieldMapping.Direction::Bidirectional, '', true, false);
    end;

Now you are good to proceed with Next Step.

You can jump to Next Step from here.

AL, AL Table Proxy Generator Tool, altpgen, Business Central, Dataverse, Extension, Generator, Integration, Page, Proxy, Table, Tool

Using AL Table Proxy Generator Tool to create Integration Table(s) in Business Central for the Dataverse table

This is the Sixth post in the series. If you want to go to previous post click here.

From the series of steps this post is dedicated to Step-5:

As a fifth Step we will Create Integration Table(s) in Business Central for the Dataverse table created in Step-4

When table(s) are present in Microsoft Dataverse, but not in Business Central, this tool can be run to generate integration or proxy table(s) for the specified table(s).

The AL Table Proxy Generator tool you can find in AL Language extension by name altpgen.exe in the equivalent folder [C:\Users\ashwi\.vscode\extensions\ms-dynamics-smb.al-7.4.502459\bin\]

Run PowerShell ISE as Administrator

Change to folder containing altpgen.exe

Above command should be single line, I have break for clarity of parameters. Below is the sample command.

.\altpgen -project:"C:\Userdata\AL Project\DataVerseIntegration" -packagecachepath:"C:\Userdata\AL Project\DataVerseIntegration\packagecachepath" -serviceuri:"https://xxxxxxxxxxx.crm8.dynamics.com/" -entities:cr95d_prospects -baseid:50125 -tabletype:CDS

When you run the command, it will ask for authentication, provide and continue.

Once you Accept the Permissions request, you can see the output of the command.

Don’t worry for warnings, Your AL file will be generated in specified folder.

Below is the sample of generated file, it is suggested to generate this file using the tool, don’t try to create manually.

table 50126 "CDS cr95d_Prospects"
{
  ExternalName = 'cr95d_prospects';
  TableType = CDS;
  Description = '';

  fields
  {
    field(1;cr95d_ProspectsId;GUID)
    {
      ExternalName = 'cr95d_prospectsid';
      ExternalType = 'Uniqueidentifier';
      ExternalAccess = Insert;
      Description = 'Unique identifier for entity instances';
      Caption = 'Prospects';
    }
    field(2;CreatedOn;Datetime)
    {
      ExternalName = 'createdon';
      ExternalType = 'DateTime';
      ExternalAccess = Read;
      Description = 'Date and time when the record was created.';
      Caption = 'Created On';
    }
    field(4;ModifiedOn;Datetime)
    {
      ExternalName = 'modifiedon';
      ExternalType = 'DateTime';
      ExternalAccess = Read;
      Description = 'Date and time when the record was modified.';
      Caption = 'Modified On';
    }
    field(24;statecode;Option)
    {
      ExternalName = 'statecode';
      ExternalType = 'State';
      ExternalAccess = Modify;
      Description = 'Status of the Prospects';
      Caption = 'Status';
      InitValue = " ";
      OptionMembers = " ", Active, Inactive;
      OptionOrdinalValues = -1, 0, 1;
    }
    field(26;statuscode;Option)
    {
      ExternalName = 'statuscode';
      ExternalType = 'Status';
      Description = 'Reason for the status of the Prospects';
      Caption = 'Status Reason';
      InitValue = " ";
      OptionMembers = " ", Active, Inactive;
      OptionOrdinalValues = -1, 1, 2;
    }
    field(28;VersionNumber;BigInteger)
    {
      ExternalName = 'versionnumber';
      ExternalType = 'BigInt';
      ExternalAccess = Read;
      Description = 'Version Number';
      Caption = 'Version Number';
    }
    field(29;ImportSequenceNumber;Integer)
    {
      ExternalName = 'importsequencenumber';
      ExternalType = 'Integer';
      ExternalAccess = Insert;
      Description = 'Sequence number of the import that created this record.';
      Caption = 'Import Sequence Number';
    }
    field(30;OverriddenCreatedOn;Date)
    {
      ExternalName = 'overriddencreatedon';
      ExternalType = 'DateTime';
      ExternalAccess = Insert;
      Description = 'Date and time that the record was migrated.';
      Caption = 'Record Created On';
    }
    field(31;TimeZoneRuleVersionNumber;Integer)
    {
      ExternalName = 'timezoneruleversionnumber';
      ExternalType = 'Integer';
      Description = 'For internal use only.';
      Caption = 'Time Zone Rule Version Number';
    }
    field(32;UTCConversionTimeZoneCode;Integer)
    {
      ExternalName = 'utcconversiontimezonecode';
      ExternalType = 'Integer';
      Description = 'Time zone code that was in use when the record was created.';
      Caption = 'UTC Conversion Time Zone Code';
    }
    field(33;cr95d_ProspectName;Text[100])
    {
      ExternalName = 'cr95d_prospectname';
      ExternalType = 'String';
      Description = 'Required name field';
      Caption = 'Prospect Name';
    }
    field(34;cr95d_ContractAmount;Decimal)
    {
      ExternalName = 'cr95d_contractamount';
      ExternalType = 'Money';
      Description = '';
      Caption = 'Contract Amount';
    }
    field(37;ExchangeRate;Decimal)
    {
      ExternalName = 'exchangerate';
      ExternalType = 'Decimal';
      ExternalAccess = Read;
      Description = 'Exchange rate for the currency associated with the entity with respect to the base currency.';
      Caption = 'Exchange Rate';
    }
    field(38;cr95d_contractamount_Base;Decimal)
    {
      ExternalName = 'cr95d_contractamount_base';
      ExternalType = 'Money';
      ExternalAccess = Read;
      Description = 'Value of the Contract Amount in base currency.';
      Caption = 'Contract Amount (Base)';
    }
    field(39;cr95d_Probability;Integer)
    {
      ExternalName = 'cr95d_probability';
      ExternalType = 'Integer';
      Description = '';
      Caption = 'Probability';
    }
    field(40;cr95d_Stage;Option)
    {
      ExternalName = 'cr95d_stage';
      ExternalType = 'Picklist';
      Description = '';
      Caption = 'Stage';
      InitValue = Lead;
      OptionMembers = Lead, Opportunity, Won, Lost;
      OptionOrdinalValues = 256080000, 256080001, 256080002, 256080003;
    }
    field(42;cr95d_ForcastedRevenue;Decimal)
    {
      ExternalName = 'cr95d_forcastedrevenue';
      ExternalType = 'Money';
      Description = '';
      Caption = 'Forcasted Revenue';
    }
    field(43;cr95d_forcastedrevenue_Base;Decimal)
    {
      ExternalName = 'cr95d_forcastedrevenue_base';
      ExternalType = 'Money';
      ExternalAccess = Read;
      Description = 'Value of the Forcasted Revenue in base currency.';
      Caption = 'Forcasted Revenue (Base)';
    }
  }
  keys
  {
    key(PK;cr95d_ProspectsId)
    {
      Clustered = true;
    }
    key(Name;cr95d_ProspectName)
    {
    }
  }
  fieldgroups
  {
    fieldgroup(DropDown;cr95d_ProspectName)
    {
    }
  }
}

Create a Page for above table

page 50122 "CDS Prospect List"
{
    Caption = 'CDS Prospect List';
    PageType = List;
    SourceTable = "CDS cr95d_Prospects";
    Editable = false;
    ApplicationArea = All;
    UsageCategory = Lists;
    RefreshOnActivate = true;

    layout
    {
        area(Content)
        {
            repeater(Group)
            {
                field("No."; Rec.cr95d_ProspectsId)
                {
                    Caption = 'No.';
                    ApplicationArea = All;
                }
                field(Name; Rec.cr95d_ProspectName)
                {
                    Caption = 'Name';
                    ApplicationArea = All;
                }
                field(Stage; Rec.cr95d_Stage)
                {
                    Caption = 'Stage';
                    ApplicationArea = All;
                }
                field("Probability"; Rec.cr95d_Probability)
                {
                    Caption = 'Probability';
                    ApplicationArea = All;
                }
                field("Contract Amount"; Rec.cr95d_ContractAmount)
                {
                    Caption = 'Contract Amount';
                    ApplicationArea = All;
                }
                field("Contract Amount (Base)"; Rec.cr95d_contractamount_Base)
                {
                    Caption = 'Contract Amount (Base)';
                    ApplicationArea = All;
                }
                field("Forecast Revenue"; Rec.cr95d_ForcastedRevenue)
                {
                    Caption = 'Forecast Revenue';
                    ApplicationArea = All;
                }
                field("Forecast Revenue (Base)"; Rec.cr95d_forcastedrevenue_Base)
                {
                    Caption = 'Forecast Revenue (Base)';
                    ApplicationArea = All;
                }
                field("Exchange Rate"; Rec.ExchangeRate)
                {
                    Caption = 'Exchange Rate';
                    ApplicationArea = All;
                }
            }
        }
    }
}

You can read more about AL Table Proxy Generator Tool from Microsoft docs

AL Table Proxy Generator

Now you are good to proceed with Next Step.

You can jump to Next Step from here.

AL, Business Central, Dataverse, Enum, Extension, Integration, Page, Table

Create Custom table & page in Business Central

This is the Fourth post in the series. If you want to go to previous post click here.

From the series of steps this post is dedicated to Step-3:

As a third Step we will Create New Table(s) and Page(s) in Business Central

Below are the AL code for Prospect table, Prospect card page & Prospect list page that will be created in Business Central via Extension, used for Integration with Dataverse.

Table in BC to Integrate from Dataverse

table 50120 "Prospect"
{
    DataClassification = ToBeClassified;
    DrillDownPageID = "Prospects";
    fields
    {
        field(1; "No."; Code[20])
        {
            DataClassification = ToBeClassified;
        }
        field(2; "Name"; Text[50])
        {
            DataClassification = ToBeClassified;
        }
        field(5; "Probability"; Integer)
        {
            DataClassification = ToBeClassified;
        }
        field(6; "Contract Amount"; Decimal)
        {
            DataClassification = ToBeClassified;
        }
        field(7; "Contract Amount (Base)"; Decimal)
        {
            DataClassification = ToBeClassified;
        }
        field(8; "Stage"; Enum "Stage Type")
        {
            DataClassification = ToBeClassified;
        }
        field(11; "Forecast Revenue"; Decimal)
        {
            DataClassification = ToBeClassified;
        }
        field(12; "Forecast Revenue (Base)"; Decimal)
        {
            DataClassification = ToBeClassified;
        }
    }

    keys
    {
        key(key1; Name)
        {
            Clustered = true;
        }
    }
}

Card Page for above Table

page 50121 "Prospect Card"
{
    Caption = 'Prospect Card';
    PageType = Card;
    UsageCategory = Administration;
    SourceTable = "Prospect";

    layout
    {
        area(Content)
        {
            group(General)
            {
                field("Name"; Rec."Name")
                {
                    ApplicationArea = All;
                }
                field(Probability; Rec.Probability)
                {
                    ApplicationArea = All;
                }
                field(Stage; Rec.Stage)
                {
                    ApplicationArea = All;
                }
            }

            group(Details)
            {
                field("Contract Amount"; Rec."Contract Amount")
                {
                    ApplicationArea = All;
                }
                field("Contract Amount (Base)"; Rec."Contract Amount (Base)")
                {
                    ApplicationArea = All;
                }
                field("Forecast Revenue"; Rec."Forecast Revenue")
                {
                    ApplicationArea = All;
                }
                field("Forcast Revenu (Base)"; Rec."Forecast Revenue (Base)")
                {
                    ApplicationArea = All;
                }
            }
        }
    }
}

List Page for above Table

page 50120 Prospects
{
    PageType = List;
    ApplicationArea = All;
    UsageCategory = Lists;
    SourceTable = Prospect;
    Caption = 'Prospect List';
    CardPageId = "Prospect Card";
    Editable = false;

    layout
    {
        area(Content)
        {
            repeater(GroupName)
            {
                field(Name; Rec.Name)
                {
                    ApplicationArea = All;

                }
                field(Probability; Rec.Probability)
                {
                    ApplicationArea = All;

                }
                field("Contract Amount"; Rec."Contract Amount")
                {
                    ApplicationArea = All;

                }
                field("Contract Amount (Base)"; Rec."Contract Amount (Base)")
                {
                    ApplicationArea = All;

                }
                field(Stage; Rec.Stage)
                {
                    ApplicationArea = All;

                }
                field("Forcast Revenue"; Rec."Forecast Revenue")
                {
                    ApplicationArea = All;

                }
                field("Forcast Revenue (Base)"; Rec."Forecast Revenue (Base)")
                {
                    ApplicationArea = All;

                }
            }
        }
    }
}

Enum for field Stage

enum 50120 "Stage Type"
{
    Extensible = true;
    AssignmentCompatibility = true;

    value(0; "Lead") { Caption = 'Lead'; }
    value(1; "Opportunity") { Caption = 'Opportunity'; }
    value(2; "Won") { Caption = 'Won'; }
    value(3; "Lost") { Caption = 'Lost'; }
}

Now you are good to proceed with Next Step.

You can jump to Next Step from here.