Advertisements

API – Business Central Part-2

In our previous post we saw basics of API in Navision. Let’s explore further.

If you missed the earlier post you can find here API – Business Central Part-1

Continuing from where we left in previous post.

Someone asked me why we require API when we have web service in place and can achieve same OData either query or filter in same fashion.

So what I am going to explain below will answer to that query.

The API will generate a REST service which returns OData.  The API is not the same as the OData web services that we discussed in our earlier post.

There we created an OData web service based on a card page.  If there were fields that need to be displayed on a card in the client application but you do not want those fields to expose in the OData web service, you will have to create a second card page to solve this problem.  In this case, we create a separate page for our API and only for the API.  This page cannot be requested in the client application.  It’s also much better concept to separate them from the regular pages.

Also we can apply templates for default value of field, which we will discuss later in below post.

Let’s start with creating our own API.

Each resource is uniquely identified through an ID. As discussed in our earlier post. So let’s start with this, I will start with my earlier created Table LoadoutPoint and add one field ID.

api009

Any new entry in my table will have a unique ID for Loadout Point, so I have added code in OnInsert trigger of the table.

api010

To create an API, you should create a page of type API, instead of a card page or list page.

Use tpage, Page for type API snippet for page structure. You get all the bare minimum properties to be added for API Page.

api011

Then you have to define which fields you would like to include.

api012

Some important rules to be followed for API Pages:

  • Fields should be named in the APIs supported format, Any Captions cannot have spaces and special characters. Only AlphaNumeric values permitted.
  • When you insert an entity through API endpoint, Business Central don’t run OnInsert trigger on the table.
  • And we have assigned the ID for the new record there. So Add Insert(true) for OnInsert Trigger.
  • Add business logic to Modify trigger. As external user can change values through API, even the value of the primary key field.
  • Add Delete(true) for On Delete trigger. The reason same as above.

So let’s add these 3 trigger in our page too.

api013

Ok so now we have modified Table and Created new API page, now it’s time to publish our app/extension.

Use command palette to publish your app.

Now it’s time to test, let’s access our API page from client and do setup for same.

Search for API Setup Page in the client.

api014

You can define and assign your Template from Template Code field, check with available same Templates how to do it.

api015

Also the conditions when this Template should apply as discussed in earlier post also.

Now let’s access the API from outside the Navision/ Business Central.

I will use Postman to test this.

To get the list of 44 standard APIs.

https://KSD-DESKTOP:7748/BC130/api/beta/

api016

To get the list of custom APIs.

https://ksd-desktop:7748/BC130/api/ksdconsultancy/app1/v1.0/

Hope you remember when we created API page we assigned few Properties like

APIPublisher = ksdconsultancy, APIGroup = app1, APIVersion = v1.0.

Now we will use those values to access my custom APIs.

See the url those are included after /api/

api017

All information is available in JSON format and further can be confirmed that there are 1000 records. Thus, the number of records integrated here depends on the Max Page Size parameter setup in Navision Server.

What else you can do with APIs:

  • Get to fetch or List
  • Post to insert records
  • Patch to modify records
  • Delete to Delete records
  • And so on.
  • You can extend existing API Pages too, I have yet not tried.

That we may discuss in some other post. Not to complicate this topic more for now I conclude this post here.

Will come up with more details in my upcoming posts, till then keep exploring, learning and take good care of yourself.

 

Advertisements

Automated Testing in Business Central

Testing is the essential part of the software development process and Cover User Scenarios.

Developers take care of their unit tests and perhaps, some wider coverage when they deliver a finished module. When developer tests the software he only tests scenarios for which he have done development.

In manual testing, since there are usually only humans involved, there will without doubt be discrepancies in the burden that test are conducted. There’s is always the trade-off between whether or not to conduct a full test scenarios for every delivery. In most scenarios tests are performed to areas of application, those are relevant for the current release. Like why should you repeat the purchasing scenarios if you only made a change to the sales process for example?

Automated testing brings a level of insistency and repeatability to testing that is impossible to achieve with just humans. By using a tool that facilitates automated testing, you can run as many test, as many times, as you want with a guarantee that each and every test will run exactly the same way as the first time. You can actually prove that a change in the sales process will not affect the purchasing process.

The key to successful automated testing is that you can link test scenarios to user scenarios. To make your development process itself test-based, by writing proper test at the start of the development process will give you clear and concrete requirements that the software has to meet.

Repeatability of running test scenarios is another key ingredient of automated testing. Manual testing can be very tedious task that can cause a human tester to lose focus. Added project pressure can add to the temptation for tester to skip the unimportant pieces of the test scenarios. How many times do you have to make sure that you can’t enter text string in an amount field for example?

Automated testing is a predefined set of Instructions that always run, no matter what time, no matter how eager the project manager wants the results, no matter how hungry you are, the test scenario is defined and it will execute every instruction every time that the test runs.

It will run exactly the same manner each and every time. You can spin as many sessions you need and simulate real load test. You can potentially scale this up to hundreds or even thousands of users at the same time and really test the limits of your software’s capabilities. Even in larger organizations it will never be possible in a manual test situation.

Manual testing is great to prove that a new piece of software meets the requirements. But what is not always clear is whether a new change in the software has had any adverse effects on existing functionality in other areas. Whereas in case of automated testing provides the capability to prove that all test scenarios can still give you the same test results over time, whenever you make any changes to any part of the software. Since you can schedule automated tests, you can run a full system test overnight or weekend, when you come back at your desk in the next morning you can look at the outcome of the latest test run and focus on just the ones that failed.

Test that are included in the standard business central test toolkit, cover the entire application. You can run the full length of thousands of those test in a matter of hours. So, combined with a build script, you can automate the creation of a new tenant, implement your compiled app, run selected tests and then, evaluate the results in a fraction of the time, which it would take a team of manual testers to do the same thing in hours. Automated testing provides the capability to run a full test set every single day or multiple times a day. If you have that capability, why not use it?

You can organize your development process to include daily build process and include a full sweep of the entire set of tests, and almost guarantee a 100 percent success when you are ready to deliver your software.

Those working on AppSource apps, will not have a choice on matter. Automated testing is mandatory for your app source submission.

Conclusion best way to do testing will be take a fresh demo database of BC, install your app and test the user scenario. If you need to prepare any data is necessary to successfully complete the user scenarios or the test scenarios, the creation of that data should be part of the installation process of your app, and or your test app. Most important feature should be included is the ability to run them in a non-super role, it should not be mandatory to have super rights in order to use your app. Make sure you include the test for non-super users as well.

Oh!! Today lots of lecture. Let’s see how we can implement this, although writing test scripts is not a easy task, require lots of efforts to cover all scenarios and knowing the system well in advance, with clear set of inputs and outputs, else even you pass test scenario chances to fail in real word cannot be avoided.

Below are the steps we follow to create an automated test script. Below is not the full and final, it is just an idea how we can implement this, rest you have to use your experience and skills to complete as per your requirement and project need.

Not compulsory but it will be better if we can use fresh database for this task. We will have only our Extension on which we are going to run this Automated Test and the Extension which we are creating in this post for Auto Test.

Step – 1 : Nav/BC Preparation

If not already imported you need to import Set of objects to enable automated testing. You can find them on installation disk under TestToolKit folder.

tcu001

If creating a Docker Container use option –includeTestToolkit in the new NavContainer Cmdlet.

Once you are done now you can run your Test Tool

tcu002

tcu003

Hold on, we will come to this later in below post.

Step – 2 : VS Code Project Preparation

Create a New project, and add Folder Structure to arrange your files.

You can find steps in this post : Bare Minimum Steps to Start with fresh Extension Project for Business Central

We need to Specify test target as a dependency. For this it is compulsory to have the apps symbols file to make this work. Install your Extension on this database if not already deployed.

We need to import symbols for the Test Framework as well. So need to specify ‘test’ settings to the app.json file of this project. Specify minimum supported value e.g. 12.0.0.0

Once these two settings are done, now when you hit Download Symbols it will include the Symbols for your Extension and Test Toolkit Objects.

tcu004

Now you can see 2 additional package symbol files are downloaded.

  1. KSD Consultancy_MyFirstExtensionProject_1.0.0.0.app
  2. Microsoft_Test_13.0.24209.0.app

And 2 std. symbol file that gets included when you create any new Extension Project.

Step – 3 : Writing Test Codeunits

We will create a codeunit of Subtype = ‘Test

Test procedures are decorated with [Test] attribute

Your OnRun will execute first, followed by other all test procedures.

You can use [TransactionModel] attribute to specify each test procedure is in a separate database transaction.

The output will be Success or Failure.

Failure is any error that is raised by the test code or from the code which is being tested. In either case Other Test procedures will still continue.

Other Features are Test Pages and UI Handlers, we will discuss on same in some other similar post.

AssertError statement is like if I do this error should come, it happens then your test is Success. In this case Failure is actually Success as you knowingly created error.

As I told earlier also this is very complicated area, to write Test Scripts, but if you start practicing from small stuffs eventually you will learn and will able to write a good Test Scripts. You can check out other standard Test Codeunits and update your knowledge how you can write your own Test Scripts.

My sample Test Codeunit looks something like below, it is just for idea in real scenario there should be lots more.

tcu005

Step – 4 : Deploy & Run the Test App

Publish your Test App.

Go to Extension Management

tcu006

You will find 2 Extension, The Initial Extension which we created in earlier posts and the Extension we just deployed.

Now open the Test Toolkit Page – 130401

Click on Get Test Codeunits function then Select Test Codeunits

tcu007

Now Select the Codeunit we just created.

tcu008

You can select other Codeunits as per the requirement, in my case I am just going to select my Codeunit which we created in this post.

tcu009

This will list all the functions available in the Test Codeunit.

Now you can select Run all or Run Selected. To test your App, I will select Run All.

tcu010

Here is the final output of test result

tcu011

Hope you will agree the test we performed, same if done manually no one can test the same in 6 seconds as this did. And we can perform as many times, and any time.

Once your Test Codeunit in place whenever you make changes to app, you can just run the test and verify that any changes you made have not impacted the existing functionality in any manner.

To save the time in testing, you have to pay in other way in creating the test codeunit as it is not that easy to cover every user scenario in your test codeunit and will require lots of efforts.

But when you are working for App Source you have no choice, you will have to do it.

Today the post got bit longer, but this topic is very complicated and require explanation. Hope you got the starting point from this and will put your efforts to reach to your required conclusion, take help of existing codeunit, nothing will be better than those to learn how Microsoft themselves implements it.

See you again with some more topics, and if get some extra time will try to add more to this post as a second part to this post. Fact is one post is not sufficient for such a huge topic.

Till then keep exploring and learning and take care of yourself.

Control Add-In in Business Central

Today I will discuss about how we can create control add-in using VS Code & Extensions in Business Central.

We can create a control add-in the same way we created pages or code units.  In Visual Studio we can use the code snippet T control add-in to generate a new control add-in.

It will better to create a fresh Extension Project in VS Code for control add in.

Step – 1 : Preparation

Create a New project, and add Folder Structure to arrange your files.

You can find steps in this post : Bare Minimum Steps to Start with fresh Extension Project for Business Central

I will create below Folder:

  1. ControlAddIn
  2. Images
  3. JsScript
  4. Page
  5. StyleSheet

Step – 2 : Create Control Add-In

In control add-in folder I’m going to create a new control add-in.  So new file.

addin-1

Use the snippet, T control add-in, to create a control add-in.

addin-2

Give the name to your control add-in in my example I have used “WeatherControlAddIn

A control add-in works with JavaScript files that can execute some code.  The scripts property is used to reference these JavaScript files.  They can be local files or references to external files over http or HTTPS.  A very commonly used JavaScript library is jQuery.  JQuery makes it a lot easier to write JavaScript code and it reduces the lines of code significantly. In our case any such files will be saved in JsScripts folder under Extension-> Objects Folder as setup above. One file we will create for StartupScript as Start.js.

Now let’s include jQuery.  We have to download jQuery from the Internet.  So if we open our Web browser and we go to the jQuery website, we can click the download jQuery button over here.  But instead of really downloading the jQuery files, we are going to reference them online.

Open the site: https://jquery.com/

addin-3

Click on Download jQuery v3.3.1 large button as shown above.
Scroll down to find: – Microsoft CDN (Content Delivery Network)
Microsoft also has a CDN for jQuery. We take that one.
Copy the link to the latest one. Add this to our Scripts property in our control add-in.

https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.js”

Use the URL of jQuery file. There’s also a property start-up script which you can use to call a special script that runs when the page where you have implemented your control add-in is loaded.  Now let’s add our start.js script over here.  So because it’s in the folder script, we have to “Objects/JsScripts/Start.js”.  Now, there’s also a recreate and a refresh script.  We are not going to use them in this demo project, so remove them. And with the images and the style sheets properties you can specify additional style to the control add-in.

Scripts = ‘https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.3.1.js’;

StyleSheets = ‘Objects/StyleSheet/StyleSheet.css’;
StartupScript = ‘Objects/JsScripts/Start.js’;
Images = ‘Objects/Images/Weather.jpg” />

I am using dummy image to display on my control add-in, select your image accordingly and place it in Images folder.
We will look into StyleSheet.css and Start.js later in below post.

addin-4

This is how your WeatherControlAddIn.al should look like.

Step – 3 : Create Style Sheet

I will be adding a CSS file to this with the name StyleSheet.css.  In this CSS file I can apply some layout styles to give my control add-in a color or let it choose a certain font and so on and so on.  But remember there are some guidelines on which styles to apply.  I’m going to set my image to a width 200 pixels.  So in CSS, this is image.  Width, 200 pixels, and a margin top of 25 pixels.  And then I need to reference it in my style sheet properties.  This is ‘Objects/StyleSheet/StyleSheet.css’ and of course in the folder StyleSheet.

addin-5

You can apply your knowledge about stylesheets to decorate your add-in accordingly, for demo purpose I have just set the width and top margin of the image.

Similarly I have downloaded an image from internet related to weather and copied to Images Folder.

Now set the path of both the files in your control add-in as shown above.

Step – 4 : Create CardPart Page

Now, our control add-in will run in a CardPart.  So we have to create a page.  Let’s create a new file and call this WeatherCardPart.al.  This is a page.  So T page.  Let’s give it an ID and a name.  WeatherCardPart.  Now the source table will be customer.  And the page type is CardPart.

Your Page should look similar to below:

addin-6

We have added our ControlAddIn on the CardPart.

Next we will pass data from our Navision to the JQuery Script to process, to do so we have added a local procedure GetCustomer, remember above in control add-in we added signature of this procedure. Now it’s time to implement that function.

We have created a JsonObject to store our data and pass to Control Add-In.

This function gets called from OnAfterGetRecord trigger of the Page.

You may be wondering about function call QueryTempOfCity, this is the same function which we used in our earlier post to call API and get temperature of specified city then updated the Headline of the RC Page.

If you missed you can find that post here: Working with Headline Role Center Page and HTTP Call – Business Central

I have copied some functions from that post and changed a little bit and added to this page, it should be like below:

addin-7

This function will take City as parameter and query from API and return the current temperature of that city. This function is explained in referenced post above.

Step – 5 : Create Page Extension

CardPart runs in a factbox on a page.  So let’s create a page extension on the customer card.  So new page.  Let’s call this customercardextension.al. which extends the customer card.  Add a factbox in the factboxes, and this is a part — let’s give it a name.  WeatherCardPart.  And this is of type WeatherCardPart.  When adding a part or a factbox, then need to set the sub page link.  So don’t forget to set the sub page link and this is equal to the number equals field number.

addin-8

It should be similar to above.

Step – 6 : Create jQuery Script

Here comes the most interesting and difficult part as we are not regular Java Script programmer, but thanks to google, who is always there to help.

We will create our Start.js

You can apply your Java Scripts skill to enhance this, let us keep it simple for learning purpose.

We will extract the information send via GetCustomer function in JsonObject and display in our Control Add-In.

addin-9

You can say controlAddIn here as main outer container.

We have defined 4 sub containers and with unique id to reference further.

Now we add all this 4 sub-containers to the main container controlAddIn.

Get the values from the Navision CardPard GetCustomer function and decode the JsonObject Customer and extract value from it and assign to these 3 containers.

For 4th we have assigned the image path from Extension using special function Microsoft.Dynamics.NAV.GetImageResource

Step – 7 : Deploy and Test the Control Add-In

So now we are done with Creating of Control Add-In, deploy your extension by using command pallet, Publish you Extension.

Open the Customer Card and you should see your Control Add-In in action.

addin-10

addin-11

Tested successful. Here we come to the end of our today’s post.

Hope you liked and enjoyed learning the concept in this post.

Will come up with more such interesting concepts in my future posts.

Till then keep exploring and learning. Take Care of yourself.

Fieldgroup in Business Central

In today’s post we will see the usage of Fieldgroup and available options.

Today’s topic is very simple and straight forward.

Field groups are used to determine which columns you have available when you have a table relation to a field.

fg-1

Another usage of field groups is when we go to a list page in Web Client like the customer list, we have a number of views of the customer list.

fg-2

We have the normal list view, but there’s also two tiles layouts, the tall tiles and the regular tiles.  When I select one of those layouts, I can see the number of the customer, the name, the contact and two decimal values, which are the balance and the balance due.

fg-3

To have a tiles layout like this, you have to create a field group with the name brick, and then you have to specify all the fields you want to display. You can only have six fields in a tile and an image.

If the last field in your brick layout is media or media set field, in this case a picture for the customer table, then that will be the media set field which is used in the application.  So the positions of your fields are very important.

fg-4

It’s very important that your tables which are used in lists in the phone client and the tablet client, that you define a brick layout, because it’s a way that you can manage how, where and what information needs to be displayed.

Hope you find the information useful, and practice accordingly.

See you again in next post with some new topic, tips & tricks.

Till then keep exploring and learning, take good care of yourself.

File Handling using Stream – Business Central

Today in this post we will discuss about using Stream to Export or Import Files or in other words File handling using Streams.

First Example I am discussing about is how to Import Image to Item Picture.

First part of the code checks for if any existing Picture in the records Picture field, here we use Count to check, because Picture field is defined as MediaSet can hold multiple picture, so giving warning for Overwrite.

In Second part we are Uploading the Selected Image to the InStream.

Finally we clear the Picture field and load Picture from InStream, here file name will be used as description for the image.  And save the record post importing of the Image.

Below code sequence is self explanatory.

StreamImpImage

In Second example we are Exporting the image from the record, any/all images stored in Picture field of the Item record.

Again we are testing with Count if any Image stored, else flag the Error nothing to Export as record don’t have any picture stored.

As told above since it is MediasSet type so possibility of more than one Image may have been stored, so we setup for loop to access all of them.

In TenantMedia table all Images are stored with unique GUID, so we get them each by Item(index).

Calcfields used to load the content in memory and final checking if it HASVALUE.

We build the filename as Item_Image1.ext, we will look into GetImgFileExt function below.

Next we load the Image in InStream.

Finally we save the Image on disk by specified filename.

StreamExpImg

This below function we use to find right extension of the file from TenantMedia field Mime Type.

StreamGetFileExt

In last and below function we are using TempBlob Table and Stream to handle file.

We create the OutStream of BlobTable Blob Field, set it as destination for my Export XML Port.

Further creating the InStream we are transferring the content of Blob to the File.

StreamExportContact

Hope you will start using this technique in your future projects, when working with File Handling.

We will discuss on other concepts in our upcoming posts.

Not sure if this is my Last post for this year, so wishing you Happy New Year 2019 in advance.

Keep practicing and learning, see you again in my next post.

Till then bye, take good care of your self and remain safe.

 

Enabling Multilanguage Support to Extensions – Business Central

Microsoft Dynamics 365 Business Central is Multilanguage enabled, which means that you can display the user interface (UI) in different language.

To add a new language to the extension you have built, you must first enable the generation of XLIFF files.

The XLIFF file extension is .xlf.

The support for using the ML properties, such as CaptionML and TooltipML, is being deprecated, so it is recommended to refactor your extension to use the corresponding property, such as Caption or Tooltip, which is being picked up in the .xlf file.

You can use the .xlf translation files approach only for objects from your extension.

It’s an XML-based format used to standardize localization.

Step – 1

To be able to work with translation files, you need to add a Feature to the app.json file.

Trans-1

This Feature is TranslationFile.

Step – 2

When we save our app.json file, we can see immediately that we get some warnings.

Trans-2

This warning is telling us that the Multilanguage syntax is being deprecated and that we have to update to the new syntax.

The new syntax requires us to remove all the ML properties, such as the caption ML and the option caption ML, and we have to use a regular Caption and OptionCaption properties.

We use Labels at place of Text Constants.

Trans-3

Let’s fix these issues. Any ML properties like Caption ML, Option Caption ML or Text Constants. Replace them with Caption and Label.

Before we start some important points:

  • The New translation process decouples translation from development.
  • New Label syntax – Default translation & Some attributes.
  • Translation file can be combined with the extensions to support Multilanguage.
  • Caption & CaptionML cannot be used simultaneously.
  • Label syntax have comment, locked and maxLength optional parameters.
  • Same syntax for Captions and Labels.

Here after fixing the above errors:

Trans-4

All errors resolved from my Project.

In Nutshell use only Caption, OptionCaption & Label, all translation will be done outside developer environment in xlf file, no more defining in objects.

Step – 3

Build your Package, choose AL:Package.

Trans-5

Once your Package is created error free, you will see new Folder Translations with one xlf file is created.

Every time you build your Package this file gets overwritten. So be cautious.

When you perform your translation make a copy of this file and save with new Name then perform your translation.

Means Translation task will be last process in your Extension building process.

If you add more Captions or Labels later then you will have to take care of them and populate in all of your Language translation Files.

No of Languages your extension supports, you will have that much of translation files and is packaged with your package, no separate installation like in older versions is required to enable MultiLanguage.

Step – 4

Let’s see what this xlf file looks like:

Trans-6

It is in xml format.

If you see “<file datatype=”xml”” you will get your Source-language & target-language. Source & Target is set to same Language.

“<trans-unit id” Specifies each of you Caption and Labels defined in you objects.

“<source>” node specifies Caption or Label in source Language.

You will have to add your “<target>” language translation.

Step – 5

Let make copy of this file in all the supported languages you want.

For example:

Trans-7

I have made 2 files en-US & nl-BE. Naming convention is for your understanding purpose only.

Now you can handover these files to translator and he can perform translation in required language outside your development environment.

You code/IP is safe from external agencies whom you give for translation.

Only what is required for this will be:

[1] Update your Target Language in below line as:

<file datatype=”xml” source-language=”en-US” target-language=”en-US” original=”MyFirstExtensionProject”>

To

<file datatype=”xml” source-language=”en-US” target-language=”nl-BE” original=”MyFirstExtensionProject”>

[2] For every

<source>…</source> add <target>…</target>

<source>Loadout Point</source>

<target>Loadout-punt</target>

There are number of tools available on internet which supports xlf file and give ease your work of translation.

Step – 5

Once you are done with your translation, copy all the translated file to the Translation folder and Build your Solution and deploy on Server.

Change the Language of Client to Dutch and run your Object:

Trans-8

I have translated only one caption shown in red-box.

Please read the points mentioned in the post carefully.

Now you can enable MultiLanguage support for your Extensions.

I will come up with some other topic in my future post.

Till then keep exploring and Learning. Take Care of yourself.

Notifications – Business Central

Today in this post we will discuss about Notification and how to implement.

First let us see, what are Notifications?

  • Non-intrusive message
  • Differs from the message initiated by the MESSAGE method.
  • Contextual
  • You can specify up to 4 actions
  • User can ignore and continue to work, doesn’t lock the user for immediate response.
  • Works with any client

Messages are modal, which means users are typically required to address the message and take some form of corrective action before they continue working. On the other hand, notifications are non-modal. Their purpose is to give users information about a current situation, but do not require any immediate action or block users from continuing with their current task.

Not-1

Tips for Create Notifications

  • Always use a unique ID, can be any GUID
  • ADDACTION points to a function
  • Arguments are case-sensitive literal
  • Functions must be global
  • Function must accept a Notification as parameter
  • Use SETDATA and GETDATA to exchange information between the sending and handling function.

Using Notification and NotificationScope data types and methods you can add code to send notifications to the users.

var

MyNotification : Notification;

Available methods are as below:

Method Description
MESSAGE Specifies the content of the notification that appears in the UI.

MyNotification.Message := ‘This will be shown as Notification’

SCOPE Specifies the scope in which the notification appears.

MyNotification.SCOPE := NOTIFICATIONSCOPE::LocalScope;

SEND Sends the notification to be displayed by the client.

MyNotification.SEND

ADDACTION Adds an action on the notification.

MyNotification.ADDACTION(‘Action 1’, CODEUNIT::”My Action Handler Codeunit”, “RunMyAction1’);

SETDATA Sets a data property value for the notification

MyNotification.SETDATA(‘CustomerNo’,Customer.”No.”);

GETDATA Gets a data property value from the notification.

MYNotification.GETDATA(‘CustomerNo’);

RECALL Recalls a sent notification.

Without going further any more in theory, let’s check how we can enable Notification.

Step – 1

Create a Codeunit to handle the Actions for Notification.

As usual we create a new Codeunit in our Extension Project.

codeunit 50101 NotificationRaiseAndHandel

Step – 2

Raise the Notification

You can Raise the Notification on Specific Page or can subscribe to the Events of that Page and write your code.

I am using the Subscription way to Raise my Notification.

For Demo purpose I am subscribing to OnOpen Event of the Page, in actual you need to decide from which action/event you wish to raise this Notification.

Code are self-explanatory, so no need special commentary.

  • I am checking for Company Info Setup we created in our earlier post if it is complete or not and then inform user about you Company Information is not completed and give him the option if he wish to complete that activity.

[EventSubscriber(ObjectType::Page, Page::”Sales Order”, ‘OnOpenPageEvent’,

”, true, true)]

local procedure CheckCompanyInfo(var Rec: Record “Sales Header”)

var

CompInfo: Record “Company Information”;

MyNotification: Notification;

begin

if compinfo.get then

if (compinfo.name <> ”) and (compinfo.”E-Mail” <> ”) then

EXIT;

MyNotification.Id := FORMAT(CreateGuid, 0, 9);

MyNotification.Scope := NotificationScope::LocalScope;

MyNotification.Message := ‘Company Information Incomplete.’;

MyNotification.AddAction(‘Open Company Information’, 50101,

‘DisplayCompanyInfoWizard’);

MyNotification.Send;

end;

  •  I am checking the Credit Limit of the customer if it is low, attracting attention towards it and giving him chance to update the Credit Limit.

   [EventSubscriber(ObjectType::Page, Page::”Sales Order”, ‘OnOpenPageEvent’,

”, true, true)]

local procedure CheckCreditBalance(var Rec: Record “Sales Header”)

var

Customer: Record Customer;

MyNotification: Notification;

Text001: TextConst ENU = ‘Balance Exceeds Credit Limit.’;

Text002: TextConst ENU = ‘Wish to change Credit Limit?’;

begin

Customer.Get(Rec.”Sell-to Customer No.”);

Customer.CalcFields(“Balance (LCY)”);

if Customer.”Balance (LCY)” > Customer.”Credit Limit (LCY)” then begin

MyNotification.Message(Text001);

MyNotification.Scope := NotificationScope::LocalScope;

MyNotification.SetData(‘CustomerNumber’, Customer.”No.”);

MyNotification.AddAction(Text002, 50101, ‘OpenCustomer’);

MyNotification.Send;

end;

end;

Step – 3

Handle the Action

Write the procedure which will respond to Actions.

   procedure DisplayCompanyInfoWizard(MyNotification: Notification)

var

CompInfo: Record “Company Information”;

begin

Page.Run(Page::CompanyInfoWizard);

end;

   procedure OpenCustomer(MyNotification: Notification)

var

CustomerNo: Text;

Customer: Record Customer;

CustomerCard: Page “Customer Card”;

begin

CustomerNo := MyNotification.GetData(‘CustomerNumber’);

if Customer.Get(CustomerNo) then begin

CustomerCard.SetRecord(Customer);

CustomerCard.RunModal;

end else begin

ERROR(‘Customer %1 not found.’, CustomerNo);

end;

end;

Here is the complete Code:

Not-2

Step – 4

Publish the Extension

To Publish choose AL:Publish from command Pallet.

Step – 5

Test the Solution.

Open the Sales Order Page and you will see the Message as shared above. Keep in mind this is just for demo, this is not the right place from where such Notifications will be raised, in real scenario you need to raise these Notifications from appropriate action/event. Now you know the basics can build your own logic around.

Will come up with some more Development Tips in my future posts.

Enjoy coding and learning. Take Care of yourself.

 

Event driven Programming – Business Central

You can use events to design your application. Below are the benefits of using this model.

  1. You can lower the cost of code modifications and upgrades.
  2. You can customize functionality without modifying the original application.
  3. Your program will react to specific actions or behaviours of original application.

E-2

The following table describes all the different event types:

Event types Description
BusinessEvent Specifies the method to be business type event publisher.
IntegrationEvent Specifies the method to be integration type event publisher.
Global Global events are predefined system events.
Trigger Trigger events are published by the runtime.

You program events in the application to run customized behaviour when they occur.

E-1

What are Events?

A thing that happens. Event is declared by an AL method, which is referred to as event publisher function. Publisher method have only signature only and does not execute any code.

Publisher is the object that contains event publisher methods that declares the event. It serves as hook-up point in application, where subscribers use these points to extend the functionality, without even making any changes to the base application.

Only publishing an event do nothing in application, these events must be raised for subscribers to respond.

Especially Business and Integration type events must be published and raised, you need to create event publisher functions and add them to the objects manually.

Trigger events which occurs on Table & Page operations, are automatically published and raised by system at runtime, so no coding is required to publish them.

Subscriber is an AL method that subscribes to even publisher method, and logic to handle the event is implement.

E-3

Creating an event publisher method to publish business and integration events

Creating event publisher method is similar to other methods you define in AL. In addition some specific properties and few restrictions.

  • Can not include any code except comments.
  • You cannot define return values, variables or text constants.

You can define event publisher in any objects new or in existing objects and of any type of objects like codeunit, page or table.

If you define even as local then it will not be available for subscribers.

[IntegrationEvent(IncludeSender,GlobalVarAccess)]

local procedure MyProcedure()

begin

end;

[BusinessEvent(IncludeSender)]

local procedure MyProcedure()

begin

end;

Feel free to add as much of parameters and of any type as required. However it is advised not to include unnecessary parameters to Business events.

Raising Events

You need to modify the application to raise the event where ever it is needed. You call the event publisher method, same way you call any other methods in AL.

When the execution hits the evet publisher method, all event subscriber method that subscribe to the event are executed. Limitation will be you can not specify the order in which subscriber method will run, subscribers will be picked one at a time and in random order.

E-4

Subscriber Method

You can create new or use existing codeunits to define subscriber methods.

[EventSubscriber(ObjectType::Codeunit, Codeunit::, ‘OnSomeEvent’, ‘ElementName’, SkipOnMissingLicense, SkipOnMissingPermission)]

local procedure MyProcedure()

begin

end;

Add code to the method for handling the event.

Don’t worry at this point we will go through complete process programmatically in our next upcoming posts.

How to find which event to subscribe, and where to write our code.

Similar to earlier days we used Code Coverage, same way we have Event Recorder in Business Central.

Search for Event Recorder in RTC or alternatively you can launch from VS Code from Command Palate AL: Open Events Recorder.

Let’s look at a small example of finding Events.

I want to know what all events hit or available to subscribe when Sales-Order is Re-Opened.

Step-1: Open the Event Recorder and Click on Start.

E-5

Step-2: Perform Sales-Order -> Reopen

Step-3: Click on Stop.

E-6

Step-4: Scan from the list of events that you find suitable, to know how to subscribe to that event you can find AL Code. (Get AL Snippet)

E-7

All the recorded events display in the order they were called. The Event Recorder page provides information on the events that were raised including the details whether the raised events were trigger events or custom events. The custom events are either Business Events or Integration Events.

You can identify the Event types, additionally, you can discover which object types and methods raised the events with the details like calling methods, object types, and object names.

Readiness to Event:

  • Redesign your on prem to an event-based approach in C/AL.
  • This will prove to be best preparation for moving to VS Code AL extension.
  • You will be able to find any issues in your code that you need to refactor.
  • Next step will be to Lift your on prem product to VS Code AL extension.
  • Then extension can be published as a MSDY365 Business Central app.

Now you know about basics of Events. Understand Publisher, Raising Events and Subscribing to Events. Also how to trace and find suitable events to subscribe for your customization over base application.

Before we end the post let’s have a Recap to Events

Publish:

  • Announcement by the application
  • Function without code
  • Exposes the event to the outside

Raise:

  • Specifies exactly when the event happens
  • Call to the Publisher Function

Subscribe:

  • React to the event
  • Must be in codeunit, tableextension or pageextension.

Note: Raise order specified in code, Subscribe order undefined.

We will look into practical approach in our next post.

 

Creating a Wizard Page in AL for Business Central

In today’s post we will learn to create Wizards.

First Let us understand why we use wizards.

  • We can define wizard as series of user input screens or steps.
  • You can show/hide options for each step based on previous step selection that is relevant to complete any setup process.
  • User can navigate between steps with Next and Previous buttons.
  • In Web Client it shows buttons with specific styling.
  • We define Page with type NavigatePage.
  • Plays crucial part in Assisted Setup.

Without going into much theory let’s start creating a Wizard Page.

Step: 1 –

Create a New Page of type NavigatePage.

CI-1

Create *.al file in your VSCode Project, you can use tpage snippet.

Set the Unique available ID in your database and Extension.

Give meaningful name to your file.

Set the PageType property to NavigatePage.

Set SourceTable property to the base table in my case “Company Information”

Step: 2 –

Add a Group for each Step you wish for your Setup, in my case I am using 3 Step.

Create Global variable CurrentStep of type Integer, this will help making decision on which step you are currently and act accordingly.

CI-2

On each Group, Set the Visible property with an expression:

Visible – CurrentStep = 1;

And so on.

Step: 3 –

Create a sub-group inside the steps and set the suitable Caption.

Set InstructionalText to provide guidance

Add fields to the sub-group

CI-3

And similarly to other groups.

Step: 4 –

Add three actions to facilitate navigation.

For each action, set the InFooterBar property to true.

When this is used in combination of PageType NavigatePage, it will show action as navigation buttons.

CI-4

Step: 5 –

Create 3 global variables as Boolean, say ActionBackAllowed, ActionNextAllowed, ActionFinishAllowed

On each action, set the Enabled property to the appropriate global variable.

Set the Image property of your actions:

Back : PreviousRecord

Next : NextRecord

Finish : Approve

CI-5

Step: 6 –

Create function/procedure to SetControls, TakeStep and Set starting values in the OnOpenPage trigger.

CI-6

Step: 7 –

Now we will add OnAction trigger to the navigation actions.

CI-7

Step: 8 –

Now we will create 2 global record variables for Media Repository table and for the Media Resources table.

CI-8

Step: 9 –

Now add 2 new groups above Step 1 Group.

Add field to each group.

Set source expression to the Image field of the Media Resources variables.

Set ShowCaption property to false.

CI-9

You see error for TopBannerVisible let’s define a global variable of type Boolean.

Step: 10 –

Now we will Add a function to Load the top banner images.

Call this function from OnInit trigger.

CI-10

We are done with our base design of Wizard.

Now time to deploy and Test.

For testing purpose let’s hook it to some page and see the result.

Although it is not correct place but for testing purpose let’s add to our existing page created in earlier post “Loadout List” page and test the output.

CI-11

Added new action on “Loadout List” Page, just to check the output. I will come up with Assisted Setup in our next post and hook it there.

Now we will Build and Deploy the Extension and review what we created.

CI-12

Access your Loadout Point List Page from Sales Order Line and Run the Wizard.

Let’s run the same from the Web Client.

ci-13

ci-14

I will come up with linking this Wizard Page to Assisted Setup in our next post.

AL Basics – Part 6 [Publishing & Testing Extension]

Today we will see in our post how we can Publish & Test our Extension.

To be able to follow this steps discussed below you should have gone through my earlier post and your project is ready to continue from where we left in our previous post. If yet not please follow below links and continue their after to this post.

Bare Minimum Steps to Start with fresh Extension Project for Business Central

AL Basics – Part 2 [Table]

AL Basics – Part 3 [Table Continued]

AL Basics – Part 4 [Page]

AL Basics – Part 5 [Extending Table & Page]

Since we are going to continue same project, reason why I am asking to have it as we will be referencing to the objects we created in above posts.

Let’s begin with our today’s task.

Ext-7

Now we have all required basic stuffs to Publish our Extension.

To Publish your Extension first need to Build and Package your Extension.

Although you can Package & Publish in single command, follow as you feel comfortable.

Press <Ctrl> +<Shift> + <P> to access your Command Pallet.

Ext-8

Chose AL:Package to create Package.

Ext-9

At this stage your package is ready for deployment/Publish.

Next we will Chose AL:Publish from Command Pallet.

Ext-10

This will create Package and Publish to your server as given in launch.json file.

Just previous step is optional to create Package, but it is helpful in case you want to just create a package but not publish to your server, may be you have tested and creating final package for delivery to your customer.

Whatsoever, we are now ready to test our Package/Extension.

You may get below error:

The request for path /BC130/dev/metadata failed with code InternalServerError. Reason: NetFx40_LegacySecurityPolicy is enabled and must be turned off in the Microsoft.Dynamics.Nav.Server.exe.config file.

Locate the file from installation folder in my case: C:\Program Files\Microsoft Dynamics 365 Business Central\130\Service

Ext-11

Set value to false save and replace the config file.

Restart your Service, and try publishing again.

You may get error:

Error: Could not open the specified startup page. Please check that the server configuration key PublicWebBaseUrl has been properly set.

That’s not a problem you can ignore it, actually it is trying to open WebClient and launch the Object you specified in launch.json file.

Open your Client and browse Extension Management.

Ext-12

Your Extension is published, & you can check the information that you provided in app.json file is visible.

Now Let’s Test our Extension.

If you remember we have integration point on Sales order line, so to see our extension in action we need to check our Sales Order Line.

Ext-13

You can see the fields that we added in our Page Extension is visible on Sales Order Line.

You can add your data and start using the extension.

If you remember we also added Appointment Calendar Setup Page to the action on Loadout Point Page.

Ext-14

If you check the Objects in your database you will not find these objects in Object designer, so where is my all data stored & saved.

To find them you need to check in your SQL database.

Your Tables are name defined with postfix your application ID.

Sales Line Extended Table data.

Ext-15

Loadout Point Table data.

Ext-16

Working Calendar Time Slot.

Ext-17

Appointment Calendar Setup.

Ext-18

Hope you enjoyed Publishing and playing around with your First Extension.

I will come up with more advanced features and tips on Extensions in upcoming posts.

Keep Learning, remain safe and stay tuned for more in upcoming posts.

Previous Older Entries

Important

Most of the contents you find in this blog will be either inherited from MSDN or Navision Developer IT Pro Help. Some places images are also directly taken from these sites. Purpose is simple to try those stuffs and re-produce adding few things as per my understanding to make easy understanding for others and quick reference.

Here nothing under my own brand or authorship of the content. At any point of time we are just promoting Microsoft stuffs nothing personnel with same.

Hope stuffs used here will not violate any copyright agreement with them. In case by mistake or in-intestinally it happens and the Microsoft feels these should not be used Microsoft have full right to inform me about same and will be glad to take down any such content which may be violating the norms.

Purpose is to promote Navision and share with community.

FB Profile

Like FB Page

%d bloggers like this: