Saturday, December 19, 2020

GST E-Invoice API Integration Explained

Dear Reader, GSPs/ASPs & Dynamics NAV Service Provider/Consultants are too busy to integrate E-Invoice solutions. Taxpayers with Turnover between Rs 100 Cr- Rs 500 Cr can contact the GSP / ERPs for the willingness to integrate the e-Invoice APIs through them.

Lots of solutions being offered. Customers are in rush to get it done ASAP as dead line is approaching.

Mostly solution are opted by customer:

  1. API : Plain Text  
  2. API : With Encryption & Decryption
  3. SFTP file transfer (Excel/CSV/JSON)
Further solutions are offered with two type of schema:
  1. GSP's own schema
  2. Government Compatible
Below I am explaining solution step by step, how to integrate E-Invoice APIs.

Hope all of us are aware about Microsoft has already given solution (can be checked in recent Cumulative updates & can be found on Posted Sales Invoice / Credit Memo):
  1. Generate IRN
  2. Export Json File
  3. Import Json File
There is a codeunit ID; 16511 with Name: e-Invoice, for export & import JSON request & response based on Government Schema (based on NIC portal & can be checked here). Which is provided by Microsoft to export & import Json files.

So, not need to create external solution (eg. DLLs for calling API & parsing received response). API request & response can be done in NAV only using NAV Codeunits & standard .net variables of Windows .net framework & NAV add-ins.

Creating outside solution will require extra maintenance. You need to update your DLL, place DLL in add-in folder & update your NAV codes. Making such solution, you are making customer highly dependent. So, its better to write code natively in NAV for API call & response parsing which can be easily updated & deployed. 

Below are major steps to reuse NAV existing solutions:

Step 1: We have already solution available to prepare JSON structure with required data. We need to reuse this solution to fit into GSP's own schema or Govt. compatible schema. It's easy & quick to modify given Codeunit 16511 or can save in available Codeunit's ID of customer's license with different name. For example Codeunit ID: 50005 Name: e-Invoice Management.

Step 2: Create a Setup table to store GSP's API URLs & Credentials, etc. For example:


Note: You may add/modify filed as per GSP details. Create a corresponding page for this table.

Step 3: Create a log/entry table to store API request & response status & details. For Example: e-Invoice Entry


Note: Above fields are for example only. You may add/modify as per your need. Create a corresponding page for this table.

Step 4: Modify e-Invoice Management codeunit's methos "ExportAsJson(DocumentNo);" to call API & process response. Get the e-Invoice Setup and check if Integration is enabled then Call API otherwise leave the original code to save the JSON file. 

Define the below variables in function "ExportAsJson":

 Update "ExportAsJson" function as below:

 LOCAL PROCEDURE ExportAsJson@1500012(DocumentNo@1500000 : Code[20]);

    VAR

      NewStream@1055602 : InStream;
      HttpWebRequestMgt@1170000000 : Codeunit 1297;
      TempBlob@1170000003 : Record 99008535;
      HTTPStatusCode@1170000002 : DotNet "'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Net.HttpStatusCode";
      ResponseHeader@1170000001 : DotNet "'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'.System.Collections.Specialized.NameObjectCollectionBase";
      InStr@1170000004 : InStream;
      Json@1170000005 : Text;
      JSONManagement@1170000006 : Codeunit 5459;
      WasSuccess@1170000007 : Boolean;
      ErrorText@1170000008 : Text;
      TrnsIdentifier@1170000009 : Text[250];
      AckNumber@1170000014 : Text[30];
      AckDateText@1170000015 : Text[30];
      IRNText@1170000010 : Text[250];
      SignedQR@1170000011 : Text;
      SignedInv@1170000012 : Text;     
      eInvoiceEntry@1170000016 : Record 50051;
      OStream@1170000017 : OutStream;
      RequestText@1170000018 : Text;
      QRPayload@1000000001 : Text;
      IRNStatus@1000000002 : Text;
      eInvoiceSetup@1000 : Record 50050;
      AuthToken@1004 : Text[250];
      SuccessText@1000000004 : Text[10];
      QRCodeFileName@1000000005 : Text;
      FileMgmt@1000000006 : Codeunit 419;
                  ArrayString@1000000009 : Text; 
      JObject@1000000008 : DotNet "'Newtonsoft.Json'.Newtonsoft.Json.Linq.JObject";
      JSONArray@1000000007 : DotNet "'Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed'.Newtonsoft.Json.Linq.JArray";
      RequestResponse@1000000010 : BigText;
    BEGIN
      eInvoiceSetup.GET();
               IF eInvoiceSetup."Integration Enabled" THEN BEGIN 
                               
      HttpWebRequestMgt.Initialize(eInvoiceSetup."Base URL" + eInvoiceSetup."
Generate E-Invoice URL");
      HttpWebRequestMgt.DisableUI();
      HttpWebRequestMgt.SetMethod('POST');
                         //Write similar function to get the Auth Token
      HttpWebRequestMgt.AddHeader('Bearer', AuthToken);
      HttpWebRequestMgt.SetContentType('application/json');
      HttpWebRequestMgt.SetReturnType('application/json');
                         RequestText := FORMAT(StringBuilder.ToString); 
      HttpWebRequestMgt.AddBodyAsText(RequestText);
      
      WasSuccess := FALSE;
      ErrorText := '';
      IRNText := '';
      SignedQR := '';
      SignedInv := '';
       AckNumber := '';
      QRPayload := '';
      IRNStatus := '';
      TempBlob.INIT;
      TempBlob.Blob.CREATEINSTREAM(InStr);
      IF HttpWebRequestMgt.GetResponse(InStr,HTTPStatusCode,ResponseHeader) THEN BEGIN
        IF FORMAT(HTTPStatusCode.ToString) IN ['OK','Ok','ok'] THEN
          WasSuccess := TRUE;
          Json := TempBlob.ReadAsText('',TEXTENCODING::UTF8);
          
          JSONManagement.InitializeFromString(Json);
          SuccessText := JSONManagement.GetValue('Success');
          IF UPPERCASE(SuccessText) = 'Y' THEN BEGIN
            AckNumber := JSONManagement.GetValue('AckNo');
            AckDateText := JSONManagement.GetValue('AckDt');
            IRNText := JSONManagement.GetValue('Irn');
            SignedInv := JSONManagement.GetValue('SignedInvoice');
            SignedQR := JSONManagement.GetValue('SignedQRCode');
            IRNStatus := JSONManagement.GetValue('Status');
          END ELSE BEGIN
            JObject := JObject.JObject();
            JSONManagement.GetJSONObject(JObject);
            ArrayString := JObject.SelectToken('ErrorDetails').ToString;
            CLEAR(JSONManagement);
            CLEAR(JObject);
            JObject := JObject.JObject();
            JSONArray := JSONArray.JArray();
            JSONManagement.InitializeCollection(ArrayString);
            JSONManagement.GetJsonArray(JSONArray);
            FOREACH JObject IN  JSONArray DO BEGIN
              ErrorText := JObject.GetValue('error_message').ToString;
            END
          END;
      END ELSE
        SuccessText := 'N';
 
      //Create Entry
      eInvoiceEntry.INIT;
      IF IsInvoice THEN
        eInvoiceEntry."Document Type" := eInvoiceEntry."Document Type"::Invoice
      ELSE
        eInvoiceEntry."Document Type" := eInvoiceEntry."Document Type"::CrMemo;
      eInvoiceEntry."Document No." := DocumentNo;
      
      CLEAR(RequestResponse);
      RequestResponse.ADDTEXT(RequestText);
      eInvoiceEntry."Request JSON".CREATEOUTSTREAM(OStream);
      RequestResponse.WRITE(OStream);
      
      CLEAR(RequestResponse);
      RequestResponse.ADDTEXT(Json);
      eInvoiceEntry."Response JSON".CREATEOUTSTREAM(OStream);
      RequestResponse.WRITE(OStream);
     
      IF NOT eInvoiceEntry.INSERT THEN
        eInvoiceEntry.MODIFY;
     
      IF UPPERCASE(SuccessText) = 'Y' THEN BEGIN
        QRCodeFileName := GetQRCode(SignedQR);
        QRCodeFileName := MoveToMagicPath(QRCodeFileName); // To avoid confirmation dialogue on RTC
        CLEAR(TempBlob);
        FileMgmt.BLOBImport(TempBlob,QRCodeFileName);
        IF TempBlob.Blob.HASVALUE THEN BEGIN
          eInvoiceEntry."QR Code Image" := TempBlob.Blob;
        END;
        eInvoiceEntry.Status := eInvoiceEntry.Status::Generated;
        eInvoiceEntry."Acknowledgment No." := AckNumber;
        eInvoiceEntry."Acknowledgment Date" := AckDateText;
        eInvoiceEntry.IRN := IRNText;
        eInvoiceEntry."IRN Status" := IRNStatus;
        eInvoiceEntry.SignedQRWriteAsText(SignedQR,TEXTENCODING::UTF8);
        eInvoiceEntry.SignedInvWriteAsText(SignedInv,TEXTENCODING::UTF8);
        eInvoiceEntry."QR Code".CREATEOUTSTREAM(OStream,TEXTENCODING::UTF8);
        OStream.WRITETEXT(QRPayload,STRLEN(QRPayload));
      END ELSE BEGIN
        eInvoiceEntry.Status := eInvoiceEntry.Status::Fail;
        eInvoiceEntry."Error Message" := COPYSTR(ErrorText,1,250);
      END;
      eInvoiceEntry.RequestWriteAsText(RequestText,TEXTENCODING::UTF8);
      eInvoiceEntry.ResponseWriteAsText(Json,TEXTENCODING::UTF8);
      eInvoiceEntry."Created By" := USERID;
      eInvoiceEntry."Created Date Time" := CURRENTDATETIME;
      eInvoiceEntryMODIFY;
    END ELSE BEGIN 
                   FileName := DELCHR(FileName,'=','/');
                     ServerFile := FileManagement.ServerTempFileName('.json');
                     IF FILE.EXISTS(ServerFile) THEN
                       ERASE(ServerFile);
                    TempFile.CREATE(ServerFile);
                    TempFile.CREATEOUTSTREAM(OutStrm);
                    OutStrm.WRITETEXT(DN_JSonConvert.Parse(StringBuilder.ToString).ToString);
                    TempFile.CLOSE;
                    LocalFile := FileManagement.SaveFileDialog('Select Folder to Save Json',FileName + '.Json','*.JSON|*.json');
                    IF LocalFile <> '' THEN
FileManagement.DownloadToFile(ServerFile,LocalFile); 
    END;
END;

Note: This code might not run directly, you need to change/update accordingly. Codeunit: Http Web Request Mgt., JSON Management, & File Management are sufficient to call API & easily parse response using few supporting .net variables.

Step 5: Similarly need to write code for cancel IRN. Give a button at e-Invoice Entries page.

Step 6: Finalize your solution by putting required validations to avoid errors. Check the link for validation. 

Happy to help you, pleas comment & give feedback. Or, you may contact us for further detailed information. 

Thanks for reading...


Friday, December 18, 2020

Digital selling helps Grant Thornton engage clients at scale

This year, I've shared inspiring stories of organizations responding to adversity by building digital resilience into the fabric of their operations and cultures. A common thread between these organizations is the agility to be better prepared for change, as well as the ability to stay focused on putting customers first. That's why it's apropos toRead more

The post Digital selling helps Grant Thornton engage clients at scale appeared first on Microsoft Dynamics 365 Blog.

Thursday, December 17, 2020

Fraud trends part 2: holiday fraud and account protection

In this blog series we are exploring the latest fraud-related events and issues on the rise in our digitized world. The first installment in the series explored account takeovers (ATO) and the $7 billion yearly loss affecting even the largest organizations. In this post, we are examining three current trends contributing to increased fraud inRead more

The post Fraud trends part 2: holiday fraud and account protection appeared first on Microsoft Dynamics 365 Blog.

Increase visibility into inventory across your supply chain

To run an effective manufacturing and distribution operation, you need an accurate understanding of your inventory and where it's located along the supply chain. What's more, having clear visibility into your inventory has become critically important as organizations shift to omnichannel order fulfillment and distribution and therefore need to manage inventory located in multiple placesRead more

The post Increase visibility into inventory across your supply chain appeared first on Microsoft Dynamics 365 Blog.

Tuesday, December 15, 2020

Ways to mitigate post-purchase fraud during the holidays

With many retailers extending online holiday sales, consumers are taking advantage of the ease of shopping from home. Online shopping can also enable more impulse buying, which in turn increases the likelihood of returns and cancelations and can open the door to abuse and fraud. Merchants need the right tools and controls to helpRead more

The post Ways to mitigate post-purchase fraud during the holidays appeared first on Microsoft Dynamics 365 Blog.

Monday, December 14, 2020

Robust warehouse execution with Dynamics 365 Supply Chain Management

To help companies execute mission-critical manufacturing and distribution processes without interruptions, we recently announced a preview for cloud and edge scale unit add-ins for Dynamics 365 Supply Chain management.

The post Robust warehouse execution with Dynamics 365 Supply Chain Management appeared first on Microsoft Dynamics 365 Blog.

Thursday, December 10, 2020

How healthcare organizations can share information securely

With the global disruption of the pandemic, healthcare organizations are particularly challenged to promote telehealth services and engage patients and providers while adhering to strict compliance and security regulations. Marketing automation and customer relationship management (CRM) tools such as Microsoft Dynamics 365 Marketing and Microsoft Dynamics 365 Customer Insights are expanding the ways in whichRead more

The post How healthcare organizations can share information securely appeared first on Microsoft Dynamics 365 Blog.

Tuesday, December 8, 2020

5 takeaways how a company turned needs into opportunities

In today's modern sales environment a trend is surfacing among B2B sellers and buyers: the desire for more authentic, personalized relationships. But despite the desire for personalized relationships, purchasing involves more people than ever, and successful sales require sellers to navigate an increasingly large group of stakeholders. While increasingly large groups of stakeholders may createRead more

The post 5 takeaways how a company turned needs into opportunities appeared first on Microsoft Dynamics 365 Blog.

Monday, December 7, 2020

3 unique success stories—building resilience into the supply chain

Even before the pandemic, organizations across industries, from manufacturing to retailers, felt the squeeze to modernize supply chain operations. The historic supply chain shock of 2020 has accelerated the need to both respond to immediate disruptions while building resilience into every layer of the supply chain. In the past, rapidly overhauling a supply chain operationRead more

The post 3 unique success stories—building resilience into the supply chain appeared first on Microsoft Dynamics 365 Blog.

Thursday, December 3, 2020

Unify ecosystem-wide data with a flexible customer data platform

In today's digital economy, delivering an exceptional customer experience across every touchpoint has quickly become a competitive differentiator. Most organizations realize if they hope to remain successful they must effectively leverage the vast amounts of data available to them in order to support the personalized engagement that customers expect. According to McKinsey, organizations that harnessRead more

The post Unify ecosystem-wide data with a flexible customer data platform appeared first on Microsoft Dynamics 365 Blog.

Tuesday, December 1, 2020

3 ways to minimize fraud this holiday season

Even in challenging times, the holiday season's irresistible deals attract both customers and fraudsters. A differentiated fraud prevention strategy is essential to keep a merchant's fraud losses minimized while letting legitimate customers continue to have a smooth shopping experience. Consumers often change buying and engagement patterns with merchants during the holiday season like shipping toRead more

The post 3 ways to minimize fraud this holiday season appeared first on Microsoft Dynamics 365 Blog.

Monday, November 30, 2020

Prepare for dimension table changes in Financial Dimension Framework

Effective December 1, 2020, for all 10.0+ versions of Dynamics 365 Financial Dimension Framework we are preventing deletion from the following Dimension tables: DimensionAttribute DimensionAttributeValue DimensionAttributeSet DimensionAttributeSetItem DimensionAttributeValueSet DimensionAttributeValueSetItem DimensionAttributeValueCombination DimensionAttributeValueGroupCombination DimensionAttributeValueGroup DimensionAttributeLevelValue This change is applied directly in the database and follows the same business logic that is used within the application. These changesRead more

The post Prepare for dimension table changes in Financial Dimension Framework appeared first on Microsoft Dynamics 365 Blog.

Realize cost savings for SMBs with Dynamics 365 Business Central

A new Total Economic Impact (TEI) from Forrester Consulting outlines the cost savings and business benefits enabled by migrating from Microsoft Dynamics NAV and Microsoft Dynamics GP to the Microsoft Dynamics 365 Business Central cloud. Cloud-based business management solutions have helped countless small and medium businesses (SMBs) realize cost savings, securely access data, boost productivity, and improve customer experiences.Read more

The post Realize cost savings for SMBs with Dynamics 365 Business Central appeared first on Microsoft Dynamics 365 Blog.

Tuesday, November 24, 2020

Boost supply chain resilience with cloud and edge scale units in Supply Chain Management

Companies that work with manufacturing and distribution need to be able to run key business processes 24/7, without interruption, and at scale. Challenges arise with unreliable connections or network latency when business processes compete for the same system resources when peak scale is required, or during periodic or regular maintenance for different regions, across timeRead more

The post Boost supply chain resilience with cloud and edge scale units in Supply Chain Management appeared first on Microsoft Dynamics 365 Blog.

How omnichannel enhances the customer experience

Omnichannel has become a dominant force in how companies meet customer expectations, and for good reason. Ninety-eight percent of Americans switch between devices on the same day, using multiple channelsvoice, social, chat, email, and SMS. Omnichannel engagement allows customers to reach out on nearly any device, on their preferred channel while managing all engagement channelsRead more

The post How omnichannel enhances the customer experience appeared first on Microsoft Dynamics 365 Blog.

Business Central - Automation APIs

Business Central provides automation APIs which can be used to create a new company on the tenant, running RapidStart packages, installing extensions, adding users to user groups and assigning permission sets to users.

Delegated admin credentials and Dynamics 365 Business Central users with permissions, can call the APIs.

For delegated admin access, you must add the Azure Active Directory (Azure AD) application to the AdminAgents group. If the Azure AD application is not added, the consent flow will show an error such as Need pre-consent. For more information, see Pre-consent your app for all your customers in the Graph documentation.

Automation APIs are placed in the microsoft/automation API namespace. In all the examples below, parameters are marked in parenthesis {}. Make sure that only valid parameters are passed.

Create a Company

To create a company, an automationCompany endpoint is available. To create a Company issue a POST request as shown in the following example.

POST https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/{apiVersion}/companies({companyId})/automationCompanies
Authorization: Bearer {token}

Content-type: application/json
{
    "name": "CRONUS India",
    "displayName": "CRONUS India Ltd.",
    "businessProfileId": ""
}

The {companyId} must be the ID of an valid company on the tenant. Issue a GET automationCompany request to fetch existing companies. 

For Example: Retrieves the properties and relationships of an automationCompany object for Dynamics 365 Business Central.

Http Request: 

GET /microsoft/automation/{apiVersion}/companies({{companyid}})/automationCompanies
Header: Authorization
Value: Bearer {token}

Http Response:

If successful, this method returns a 200 OK response code and list of automationCompany objects in the response body. For example:

{
    "id": "3496bbf8-fcae-4e48-a4f8-cb17c27de0b3",
    "name": "CRONUS India",
    "evaluationCompany": true,
    "displayName": "CRONUS India Ltd.",
    "businessProfileId": ""
}

Note: The company which is created will not be initialized.

To rename a company, issue a PATCH automationCompanies.

Upload and apply a RapidStart package

RapidStart is uploaded, installed, and applied using the APIs described below. RapidStart operations can be time consuming. To get the current status of the RapidStart packages and running operations issue a GET configurationPackages as shown in the following example.

GET https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/{apiVersion}/companies({companyId})/configurationPackages
Authorization: Bearer {token}

In the response, status for the import and apply status will be shown, as well as information about the RapidStart package.

Insert RapidStart

First step is to create the configuration package, by issuing a POST configurationPackages in the Dynamics 365 Business Central tenant. Once the configuration package is created, the RapidStart package can be uploaded. See the example below.

POST https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/{apiVersion}/companies({companyId})/configurationPackages

Authorization: Bearer {token}
Content-type: application/json
{
    "code":"{SAMPLE}",
    "packageName": "{SAMPLE}"
}


Upload RapidStart package

Once the configuration package is created, a RapidStart package can be uploaded with a PATCH configurationPackages. See the example below.

PATCH https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/{apiVersion}/companies({{companyId}})/configurationPackages('{SAMPLE}')/file('{SAMPLE}')/content

Authorization: Bearer {token}
Content-type: application/octet-stream
If-Match: *
Body: RapidStart file.


Import and apply RapidStart package

Once uploaded, the RapidStart package needs to be imported by issuing a POST on the bound action Microsoft.NAV.import.

POST https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/{apiVersion}/companies({{companyId}})/configurationPackages('SAMPLE}')/Microsoft.NAV.import

Authorization: Bearer {token}

When the RapidStart package is imported it can applied with a POST on bound action Microsoft.NAV.apply.

POST https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/{apiVersion}/companies({companyId})/configurationPackages('SAMPLE}')/Microsoft.NAV.apply

Authorization: Bearer {token}


Managing users, user groups, and permission sets

The automation APIs enable users to be set up in Dynamics 365 Business Central.

Modifying user properties

Get the current user properties by issuing a GET users. This will get the UserSecurityId needed on subsequent requests.

To modify the user, create a PATCH user request as shown in the example below.

PATCH https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/v1.0/companies({id})/users({userSecurityId})
Content-type: application/json
If-Match:*
{
    "state": "Enabled",
    "expiryDate": "2025-10-01T00:10:59.999Z"
}


Assign user permissions and user groups

To assign users to a user group, issue a POST request against the userGroupMembers entity. See the example below.

POST https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/{apiVersion}/companies({companyId})/users({userSecurityId})/userGroupMembers

Authorization: Bearer {token}
    "code": "D365 EXT. ACCOUNTANT",
    "companyName" :"CRONUS Inida"
}

To retrieve the list of user groups issue a GET userGroups. This will return the information that you need for the payload above.

Assigning permission sets is identical to adding users to user groups. GET permissionSet returns information about the available permission sets. To assign a permissionSet issue a POST userPermission as shown in the following example.

POST https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/{apiVersion}/companies({companyId})/users({userSecurityId})/userPermissions

Authorization: Bearer {token}
    "id": "SECURITY"
}

Removing the permissionSet from the user is done by issuing a DELETE userPermissions on the users entity.

Handling tenant extensions

Add-on extensions which are already published to the tenant can be installed and uninstalled. Per-tenant extensions can be uploaded and installed. To get the list of all extensions on the tenant, issue a GET extensions. This will return the packageId needed for installing and uninstalling extensions.

Installing and uninstalling published add-on extensions

There are two bound actions available on the extensions endpoint: Microsoft.NAV.install and Microsoft.NAV.uninstall.

Issue a POST extension using the bound actions. See the example below.

POST https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/{apiVersion}/companies({companyId})/extensions({packageId})/Microsoft.NAV.install

Authorization: Bearer {token}


Upload and install a per-tenant extension

Issue a PATCH against the extensionUpload endpoint to upload and install the extension.

Note: Installing per-tenant extensions using Automation APIs is only possible in SaaS.

Uninstalling the extension can be done through the bound action Microsoft.NAV.uninstall, as with the add-on extensions.

Monitoring extension installation progress

To view ongoing extension installation status, issue GET extensionDeploymentStatus as shown in the following example.

GET https://api.businesscentral.dynamics.com/v2.0/{environment name}/api/microsoft/automation/v1.0/companies({companyId})/extensionDeploymentStatus


Blog Source: Microsoft Docs

Monday, November 23, 2020

Accelerate implementations with the expanded FastTrack for Dynamics 365

Today, more than ever, your organization needs to adapt to changing business conditions with incredible speed and efficacy. Whether you're shifting to digital sales or streamlining your supply chain, Dynamics 365 plays a pivotal role in digital transformation initiatives by bringing customers and business priorities together with the next generation of CRM and ERP applications.Read more

The post Accelerate implementations with the expanded FastTrack for Dynamics 365 appeared first on Microsoft Dynamics 365 Blog.

Tips for setting up sales forecasting in Dynamics 365 Sales

Most sales organizations understand the value of maintaining an accurate sales forecast. However, many are still tracking forecasts with a time-consuming spreadsheet. This blog post provides some best practices for using forecasting capabilities in Dynamics 365 Sales to help simplify creating accurate forecasts, even during rapidly changing conditions. Benefits of sales forecasting Sales forecasting isRead more

The post Tips for setting up sales forecasting in Dynamics 365 Sales appeared first on Microsoft Dynamics 365 Blog.

Thursday, November 19, 2020

Using activity data to improve opportunity scoring predictions in Dynamics 365 Sales

Listening to the challenges many of our customers are facing with increasingly working online, we've developed new capabilities in Dynamics 365 to discover email messages, meetings, and phone call activities related to an opportunity, and then to factor these signals into the score. Capturing activities to determine opportunity health A healthy opportunity will usually haveRead more

The post Using activity data to improve opportunity scoring predictions in Dynamics 365 Sales appeared first on Microsoft Dynamics 365 Blog.

Monday, November 16, 2020

Business Central Online - Operational Limits

Make sure to take in consideration & discuss with client requirements/expectation on below parameter:

  • No. of User & Concurrent Client Connection
  • Data Handling 
  • Database Connection
  • Asynchronous Task
  • Report Data
  • Query Data
  • OData & SOPA Data

Above will help to ensure the availability and quality of Business Central services, there are limits on certain operations. Below descried limits are per-tenant limits.


The telemetry provides insight into operations for which limits were exceeded. For more information, see Monitoring and Analyzing Telemetry. 


Client Connection Limits 

Setting 

Description 

Limit 

Max concurrent calls 

The maximum number of concurrent client calls that can be active.

1000 

Max concurrent connections 

The maximum number of concurrent client connections that the service accepts. 

500 

Max number of orphaned connections 

Th maximum number of orphaned connections to be kept alive at the same time for the time that is specified by ReconnectPeriod. 

 

A connection is orphaned when the client is involuntarily disconnected from service. 

 

You can also use MaxValue as a value to indicate no limit.

20 

Reconnect period 

The time during which a client can reconnect to the service after being disconnected. 

10 minutes 

 

Data Handling Limits 

Setting 

Description 

Limit 

Max items in object graph 

The maximum number of objects to serialize or deserialize. 

10,000 

Max file size 

The maximum size of files that can be uploaded to or downloaded from the service.

350 MB 

Maximum stream read size 

The maximum number of bytes that can be read from a stream (InStream object) in a single AL read operation. Examples include READ or InStream.READTEXT method calls. This setting pertains to UTF-8 and UTF-16 text encoding; not MS-DOS encoding.

1,000,000 bytes 

 

Database Connection Limits 

Setting 

Description 

Value 

Search timeout 

The time (in seconds) that a search operation on lists in the client continues before it's stopped. When the limit is reached, the following message displays in the client: Searching for rows is taking too long. Try to search or filter using different criteria. 

10 seconds 

SQL command timeout 

The contextual time-out for a SQL command. 

30 minutes 

SQL connection idle timeout 

The time that a SQL connection can remain idle before being closed. 

minutes 

SQL connection timeout 

The time to wait for the service to connect to the database. When the time is exceeded, the attempt is canceled and an error occurs. This setting also applies to begin, rollback, and commit of transactions.

1.5 hours 

Long running SQL query threshold 

The amount of time that an SQL query can run before a warning telemetry event occurs. If this threshold is exceeded, the following event is logged: Action completed successfully, but it took longer than the given threshold.

1000 ms 

 

Asynchronous Task Limits 

Setting 

Description 

Limit 

Maximum concurrent running scheduled tasks 

The maximum number of tasks that can run simultaneously for an environment. 

 

If there are many jobs running at the same time, you might experience that the response time for clients gets slower. If the value is too low, it might take longer for scheduled tasks to process.

3 

Page background task default timeout 

The default amount of time that page background tasks can run before being canceled. Page background tasks can be also given a timeout value when enqueued at runtime. This limit is used when no timeout is provided when the page background task is enqueued.

minutes 

Page background task max timeout 

The maximum amount of time that page background tasks can run before being canceled. Page background tasks can be also given a timeout value when enqueued at runtime. If a page background task is enqueued with a timeout greater than this limit, this limit is ignored.

10 minutes 

ChildSessionsMaxConcurrency 

The maximum number of child sessions that can run concurrently per parent session. When the value is exceeded, additional child sessions will be queued and run when a slot becomes available as other child sessions are finished.

5 

ChildSessionsMaxQueueLength 

The maximum number of child sessions that can be queued per parent session. If the value is exceeded, an error occurs.

100 


Report Limits 

Setting 

Description 

Limit 

Default max documents 

The maximum number of documents that can be merged in report by default Users can override this setting on a report-basis from the report request page. If exceeded, the report will be canceled. 

 

Developers can override this setting by using MaximumDocumentCount property of a report. Client users can do the same when running a report from the report request page.

200 

Max documents 

The maximum number of documents that can be merged in report. If exceeded, the report will be canceled.

500 

Default max execution timeout 

The maximum execution time that it can take to generate a report by default. Users can override this setting on a report-basis from the report request page. If exceeded, the report will be canceled. 

 

Developers can override this setting by using the ExecutionTimeout property of a report. Client users can do the same when running a report from the report request page. 

hours 

Max execution timeout 

The maximum execution time that it can take to generate a report. If exceeded, the report will be canceled. 

12 hours 

Default max rows 

The maximum number of rows that can be processed in a report by default. Users can override this setting on a report-basis from the report request page. If exceeded, the report will be canceled. 

 

Developers can override this setting by using the MaximumDataSetSize property of a report. Client users can do the same when running a report from the report request page. 

500,000 

Max rows 

The maximum number of rows that can be processed in a report. If exceeded, the report will be canceled by the server.

1,000,000 

 

Query Limits 

Setting 

Description 

Limit 

Max execution timeout 

The maximum execution time that it can take to generate a query. If exceeded, the query will be canceled. 

30 minutes 

Max rows 

The maximum number of rows that can be processed in a query. If exceeded, the query will be canceled.

1,000,000 

 

OData Request Limits 

Setting 

Description 

Limit 

Max concurrent requests 

The maximum number of OData V4 requests the server instance can actively process at the same time. Requests that exceed the limit will wait in the queue until a time slot becomes available. 

5 

Max connections 

The maximum number of simultaneous OData requests on the server instance, including concurrent and queued requests. When the limit is exceeded, a 429 (Too Many Requests) error occurs. 

100 

Max page size 

The maximum number of entities returned per page of OData results. 

20,000 entities per page 

Max request queue size 

The maximum number of pending OData V4 requests waiting to be processed. When the limit is exceeded, a 429 (Too Many Requests) error occurs. 

95 

Rate 

The number of OData requests per minute that are allowed. An HTTP response code 429 - Too Many Requests is returned if limits are exceeded. 

Sandbox: 
300 requests/minute 
 
Production 
- 600 requests/minute 

Operation timeout 

The maximum amount of time that the service gives a single OData request. When the limit is exceeded, an HTTP response code 408 - Request Timeout is returned. 

 

After 8 minutes, the session is canceled. 

minutes 


SOAP Request Limits  

Setting 

Description 

Limit 

Max concurrent requests 

The maximum number of SOAP requests the server instance can actively process at the same time. Requests that exceed the limit will wait in the queue until a time slot becomes available. 

5 

Max connections 

The maximum number of simultaneous SOAP requests on the server instance, including concurrent and queued requests. When the limit is exceeded, a 429 (Too Many Requests) error occurs. 

100 

Max message size 

The maximum permitted size of a SOAP web service requests 

65,536 KB 

Max request queue size 

The maximum number of pending SOAP requests waiting to be processed. When the limit is exceeded, a 429 (Too Many Requests) error occurs. 

95 

Rate 

Specifies how many SOAP requests per minute are allowed. An HTTP response code 429 - Too Many Requests is returned if limits are exceeded. 

Sandbox: 
300 requests/minute 
 
Production: 
600 requests/minute 

Operation timeout 

The maximum amount of time that the service gives to a single SOAP request. When the limit is exceeded, HTTP response code 408 - Request Timeout is returned. 

 

 

Source of this article: Microsoft Docs