Why Operational Maturity Will Define the Winners of the Next Decade

The Competitive Advantage Nobody Talks About

 

For much of the past twenty years, competitive advantage was often linked to technology adoption.

 

Organizations invested in new platforms, modernized infrastructure, digitized processes, and expanded access to data. Those able to move faster frequently established meaningful advantages over their peers.

 

Today, that dynamic is changing.

 

Technology continues to evolve at an extraordinary pace, but access to innovation is becoming increasingly democratized. Capabilities that were once available only to a select group of organizations can now be deployed broadly and at scale.

 

As a result, technology alone is becoming a less reliable source of differentiation. The question facing business leaders is no longer whether innovation is available. It is whether their organizations are capable of translating innovation into measurable outcomes.

 

 

The New Constraint on Growth

 

Many organizations possess the technologies required to improve performance, increase efficiency, and create new value.

 

Yet the results achieved across businesses remain remarkably uneven.

 

The difference is rarely explained by technology itself. More often, it is explained by execution. Disconnected processes, fragmented data, inconsistent governance, and competing priorities create friction that limits the impact of even the most advanced capabilities.

 

In many cases, organizations do not struggle because they lack innovation. They struggle because their operating environment prevents innovation from scaling.

 

Maturity Creates Momentum

 

Operational maturity is often misunderstood as standardization for its own sake.

 

In reality, maturity creates the conditions for adaptability. Organizations with well-defined processes, trusted data, and aligned operating models can absorb change more effectively than those operating through fragmentation and exception management.

 

They can introduce new capabilities more quickly.

They can make decisions with greater confidence.

They can respond to market shifts with less disruption.

 

Most importantly, they can scale successful initiatives beyond isolated teams or departments.

 

This ability to consistently translate change into results is becoming a defining characteristic of high-performing organizations.

 

The Strategic Value of Foundations

 

Business leaders are often drawn to visible transformation initiatives. New technologies generate attention. New capabilities generate excitement.

 

Yet the organizations that sustain long-term performance typically invest as much effort in foundations as they do in innovation.

 

Modern business applications, integrated data environments, and standardized operating processes may not attract headlines, but they create the infrastructure through which transformation becomes possible. Organizations that have invested in connected business platforms are often better positioned to absorb change, scale innovation, and adapt to new market realities.

 

Without these foundations, change remains episodic.

 

With them, change becomes repeatable.

 

This distinction is increasingly important as the pace of technological advancement accelerates.

 

A Different Perspective on Transformation

 

Transformation is frequently discussed as a destination, a future state reached through a major initiative or implementation.

 

Today, the challenge is different. Markets evolve faster, customer expectations shift more rapidly, and new technologies continue to reshape competitive landscapes.

 

Success increasingly depends not on an organization’s ability to transform once, but on its ability to adapt continuously. That capability is built on operational maturity.

 

Looking Ahead

 

Technology will continue to advance, and access to new capabilities will continue to widen across the market.

 

As innovation becomes more accessible, organizational capability becomes more valuable. The organizations that invest in strong operational foundations today will be better positioned to adopt emerging technologies, respond to change, and sustain competitive advantage in the years ahead.

 

2024 Release Wave 2 Plans For Microsoft Dynamics 365 And Power Platform

On July 16, 2024, Microsoft published the 2024 release wave 2 plans for Microsoft Dynamics 365 and Microsoft Power Platform, a compilation of the new capabilities planned to be released between October 2024 to March 2025. This release introduces a wealth of new features designed to enhance customer understanding and improve overall user experience, showcasing Microsoft’s dedication to driving digital transformation for their customers and partners.

 

The new wave is focused on improving user productivity and streamlining processes across various business applications by employing Microsoft Copilot and cutting-edge AI technologies. These enhancements include intelligent automation, AI-powered insights, and immersive user experiences and aim to remove boundaries between data, insights, and individuals.

 

Discover the newest features that enable organisations to run more effectively and adaptably.

 

The new capabilities allow businesses to take proactive measures to address challenges and capitalise on opportunities. Examples of these include predictive analytics in supply chain management, autonomous financial processes, AI-driven sales insights and customer service enhancements.

 

Early Access Period

 

Starting July 29, 2024, customers and partners can validate the latest features in a non-production environment. These updates include user experience enhancements that will be automatically enabled in production environments by October 2024.

 

We have briefly described numerous of the features from the second release wave in this blog post’s contents.

 

Wave Highlights for Microsoft Dynamics 365

 

Microsoft Dynamics 365 Sales

 

Microsoft Dynamics 365 Sales continues to enhance customer understanding and boost sales through data, intelligence, and user-friendly experiences.

 

In this release, Microsoft are focused on including natural language copilot for summarizing information, creating a new full-screen Copilot Home with curated insights and role-specific actions, and using AI-powered insights to find leads.

 

Microsoft Copilot for Sales

 

Microsoft Copilot for Sales continues to deliver and enhance cutting-edge generative AI capabilities for sellers by enriching Copilot in Microsoft 365 capabilities with sales-specific workflows, data, and actions.

 

Microsoft will focus on using AI-powered insights to create leads, deepen the integration into Copilot in Microsoft 365, and use natural language capabilities to allow sellers to ask data-related questions of their CRM.

 

Microsoft Dynamics 365 Customer Service

 

Microsoft Dynamics 365 Customer Service will continue to empower agents to work more efficiently through new copilot capabilities such as proactive prompting, ability to access data from external systems securely with plugins, email enhancements, and AI-infused routing.

 

Microsoft Copilot for Service

 

Microsoft Copilot for Service is now generally available, bringing new capabilities to enhance user experiences. These features will be integrated across Outlook, Teams, Microsoft 365 Chat, and Copilot embedded in third-party CRMs.

 

Microsoft Dynamics 365 Field Service

 

Microsoft Dynamics 365 Field Service enables a shift from reactive to proactive and predictive service, empowering digital transformation and innovative business models.

 

Using Copilot, frontline workers will be able to retrieve critical information and initiate mixed-reality remote assist calls within Teams through Copilot.

 

Managers will be able to create, update, and manage work orders effortlessly across web, Outlook, and Teams interfaces.

 

Microsoft Dynamics 365 Finance

 

Microsoft Dynamics 365 Finance continues its journey of leading in autonomous finance, using AI to transform common end-to-end financial processes.

 

This release focuses on in-app copilot capabilities, immersive persona-based user experiences, expanding country coverage, electronic invoicing enhancements, business performance analytics and planning enhancements, and autonomous reconciliation capabilities.

 

Microsoft Copilot for Finance

 

Microsoft Copilot for Finance is expanding data reconciliation capabilities in Excel with assisted data sanitization and preparation routines. Extending variance analysis capabilities with support from additional data sources and enabling collaboration on findings with stakeholders will also be a focus in the upcoming wave.

 

Additionally, the Teams integration will facilitate collections calls with suggested scripts and automated recording of action items in the financial system.

 

Microsoft Dynamics 365 Supply Chain Management

 

Microsoft Dynamics 365 Supply Chain Management is advancing along the path of an autonomous supply chain by integrating intelligence, automation, and analytics into every facet of business procedures, thereby improving user productivity and enhancing organizational adaptability.

 

In this update, the spotlight is on improving order-promising capabilities for manufacturers. Demand planning is upgraded to incorporate forecasting with external signals, and the inclusion of Copilot weaves insights and analyses directly into workflows, identifying trends and irregularities, while also allowing for specific data inquiries at the cell level.

 

Additionally, Traceability Copilot keeps track of actual products in production and compiles a comprehensive historical record of related activities.

 

Microsoft Dynamics 365 Project Operations

 

Microsoft Dynamics 365 Project Operations is focused on enhancing usability, performance, and scalability in key areas such as project planning, invoicing, time entry, and core transaction processing.

 

The spotlight is on AI-assisted core functionality improvements in estimation, proposal generation, journals, approvals, and contract management, with added mobile capabilities and scale improvements to handle larger projects and invoices at an increased scale.

 

Finance and Operations Cross-app Capabilities

 

Finance and Operations cross-app capabilities will continue to invest in capabilities applying to Finance, Supply Chain Management, Microsoft Dynamics 365 Commerce, Microsoft Dynamics 365 Human Resources, and Project Operations.

 

Microsoft is infusing copilot experiences across applications, including natural language chat, embedded AI, and intelligent process automation, and enabling extensibility for copilot scenarios.

 

Microsoft will also bring more value and insights to finance and operations apps data and enhancements to ensure continued enterprise-grade security and compliance at scale.

 

Microsoft Dynamics 365 Human Resources

 

Microsoft Dynamics 365 Human Resources continues to build intelligence, develop automation and analytics around the hire-to-separate process, increase user productivity, and empower business agility.

 

Microsoft is enhancing recruiting with AI-driven assessments and offers management, improving experiences for employees and HR business partners in benefits and performance management, and advancing analytics, insights, and planning through business performance planning and analytics capabilities.

 

Microsoft Dynamics 365 Commerce

 

Microsoft Dynamics 365 Commerce is using the power of AI to empower retailers to streamline their operations and drive increased customer loyalty and conversions. With Copilot, retail managers, sales associates, and merchandisers will gain new AI-powered insights into customer buying patterns and preferences, recommendations for positioning and selling products, and business intelligence on store performance.

 

Improvements to the self-checkout POS make customer checkouts more efficient, and user experience updates to Store Commerce app streamline daily tasks for faster, more efficient sales and service.

 

Microsoft Dynamics 365 Business Central

 

Microsoft Dynamics 365 Business Central is focused on maintaining service reliability performance and security standards. Microsoft will continue enhancing productivity by optimizing core processes with Copilot, expanding to cover more than 170 countries, and offering enhanced reporting with more than 80 Microsoft Power BI reports.

 

Additionally, integration with Field Service will be expanded, along with new financial management features. Microsoft will also enhance development tools and governance, along with improved data privacy and compliance management.

 

Wave Highlights for Microsoft Power Platform

 

Microsoft Power Apps

 

Microsoft Power Apps will continue to transform app experiences with infused intelligence, enabling users to be more productive by using Copilot to work with data, get insights, and improve their apps.

 

Makers will continue to benefit from AI-assisted development, enabling rich and complex applications to be built with monitoring, control, and unmatched governance for admins, ensuring organizations can adopt low-code and AI transformation at scale.

 

Microsoft Power Pages

 

Microsoft Power Pages will expedite site building for a low-code maker or pro developer to build intelligent sites that reimagine the way you interact with your employees, customers, and partners.

 

Microsoft Power Automate

 

Microsoft Power Automate will continue to make it easier to build flows by using natural language and multi-modal generative AI capabilities across cloud flows and desktop flows, troubleshooting runs, and managing your automation estate with an end-to-end view.

 

This, along with improvements in process mining to jumpstart creation of automation through Microsoft 365 integration and ongoing improvements to scaling, means it’ll be easier than ever for new users to get started and scale.

 

Microsoft Copilot Studio

 

Microsoft Copilot Studio is advancing copilot capabilities and IVR support with Customer Service and will expand geographically to the United Arab Emirates and Germany.

 

Additionally, the team is improving software lifecycle management capabilities with topic-level import/export and role-based access control (RBAC), as well as enhancing governance and administration functionalities.

 

Key Dates for the 2024 Release Wave 2

 

You can access additional information regarding the key dates for the 2024 release wave 2 here.

 

If your goals are to improve and optimize your business processes, ensure data security in the cloud, make application usage simpler in the long term and seek assistance in upgrading your Dynamics 365 versions to newer versions, we are excited about the possibility for potential collaboration. Reach out to us here.

2023 Release Wave 2 Plans for Microsoft Dynamics 365 and Power Platform

On July 18, 2023, Microsoft published the 2023 release wave 2 plans for Microsoft Dynamics 365 and Microsoft Power Platform, a compilation of new capabilities planned to be released between October 2023 and March 2024.

 

The second release wave of the year offers hundreds of new features, including AI capabilities and enhancements, demonstrating Microsoft’s continued investment to power digital transformation for their customers and partners.

 

The new capabilities empower new ways to make informed decisions with AI-guided insights and suggested actions, easier ways to automate tasks and processes, and collaboration seamlessly integrated into the flow of work, plus, new low-code ways for anyone to build solutions.

2023 Release Wave 2 Features Available for Early Access Period

 

Starting July 31, 2023, company users and partners will be able to validate the latest features in a non-production environment. These features include user experience enhancements that will be automatically enabled for users in production environments during October 2023.

 

In the contents of this blog post, we have succinctly outlined a selection of the features from the second release wave.

 

Wave Highlights for Microsoft Dynamics 365

 

Microsoft Dynamics 365 Marketing

 

Microsoft Dynamics 365 Marketing will bring enhancements to Copilot features and will bring unprecedented levels of personalization to email content, images, and layouts.

 

Additionally, business-to-business (B2B) dashboards and directly assigning leads to the right sales rep will align marketers and sellers, enabling them to act as a unified team across the buying journey.

 

Microsoft Dynamics 365 Field Service

 

Microsoft Dynamics 365 Field Service updates will include new capabilities for frontline workers, service managers, and dispatchers. Microsoft will deliver several top requests such as converting quotes to work orders, enhancing inspections, and evolving resource scheduling capabilities.

 

Microsoft Dynamics 365 Sales

 

Microsoft Dynamics 365 Sales will focus on enabling sales organizations to prioritize and manage digital sales processes through enhanced sequence capabilities.

 

Microsoft will allow users to assign and monitor lead assignment status with enhanced lead assignment capabilities by providing recommendations, summarizing data, retrieving information, and performing actions in context and within the flow of work.

 

Microsoft Dynamics 365 Customer Service

 

Microsoft Dynamics 365 Customer Service will continue to empower agents to work more efficiently through Copilot capabilities, Join Me On Teams, visual enhancements to the agent workspace, ability to see live chats and voice calls in Inbox and personalizing size of conversational control.

 

Additionally, Microsoft is making enhancements to the voice channel, call dialer improvements, and routing calls to agents with longest idle time.

 

Microsoft Dynamics 365 Finance

 

Microsoft Dynamics 365 Finance is focused on enhancing organizations’ visibility into their data, continued enhancements for accounts payable and bank statement automation, and expanding out-of-the-box country coverage in Latin America.

 

Additionally, the team will deliver further automation of complex tax scenarios and e-invoicing requirements for new countries and provide organizations ability for business model expansion and agility.

 

Microsoft Dynamics 365 Supply Chain Management

 

Microsoft Dynamics 365 Supply Chain Management continues to improve and optimize business processes to deliver the agility and resilience needed for businesses to thrive in an increasingly complex business environment. The sales and procurement processes will be further enhanced, manufacturers will enjoy greater flexibility, and warehouse processes related to counting, customer returns, and product receipts will be improved.

 

Microsoft Dynamics 365 Project Operations

 

Microsoft Dynamics 365 Project Operations is investing in enhancements to services procurement scenarios and project contracting and new functionalities and scenarios in pricing models will support the evolving patterns in the service-centric economy.

 

Additionally, improvements to intelligent resource recommendations will provide suggestions based on experience, cost, and utilization across employees and subcontractors.

 

Microsoft Dynamics 365 Human Resources

 

Microsoft Dynamics 365 Human Resources will be improving recruiting experiences that target recruiters, candidates, and hiring managers. Microsoft will expand the human capital management ecosystem to include learning management system integration through public APIs using Microsoft Dataverse along with expanding our payroll partner network.

 

Microsoft Dynamics 365 Commerce

 

Microsoft Dynamics 365 Commerce uses the power of AI to enable the effortless creation of engaging product content for digital commerce sites. New B2B investments allow distributors to view, accept, and reject orders from a centralized dashboard that enables B2B sellers, distributors, and buyers to all work in the same place.

 

Wave Highlights for Power Platform

 

Microsoft Power Apps

 

Microsoft Power Apps is expanding the use of Copilot to bring AI-assisted experiences to increase developer productivity, bring natural language to all users, and give insights to admins. Microsoft will bring modern controls and rich collaborative experiences to users, as well as improved deployment and governance support to ensure low-code can be enabled organization wide.

 

Microsoft Power Pages

 

Microsoft Power Pages continues to make strides in the Copilot maker experience to enable building a site. Managed environments will include Power Pages capabilities for maker usage and onboarding. For data, you will be able to connect easily to data where it exists today. Low-code makers can collaborate and detect co-presence.

 

Microsoft Power Automate

 

Microsoft Power Automate will continue to make it easier to get started building new flows by using natural language across cloud flows and desktop flows, and by improving process mining to jumpstart creation of automation and authoring experiences. Additionally, Microsoft is making it easier to manage work at scale by introducing unified activity view and deeper notifications on capabilities across the product.

 

Microsoft Power Virtual Agents

 

Microsoft Power Virtual Agents will bring general availability for capabilities including Multi-Lingual bot support, Generative Answers and Actions, Standalone interactive voice response (IVR) and IVR integration with Dynamics 365 Customer Service, and integration with the Conversational Language Understanding service. Additionally, Microsoft will offer their customers new Enterprise Trust capabilities.

 

Key Dates for the 2023 Release Wave 2

 

Here you can access additional information regarding the key dates for the 2023 release wave 2.

 

If your aim is to enhance and optimize your business processes, simplify application usage for long-term convenience, ensure data security in the cloud, and seek assistance in upgrading your Dynamics 365 systems to newer versions, we welcome the opportunity for potential collaboration. Reach out to us here.

Electronic Reporting in D365: Replacing Existing Field with a Financial Dimension in an Outgoing Report Structured as Zip of Text Files

ER is a tool that you can use to configure formats for both incoming and outgoing electronic documents in accordance with the legal requirements of various countries/regions. ER lets you manage these formats during their lifecycle.

 

For example, you can adopt new regulatory requirements, and generate business documents in the required format to electronically exchange information with government bodies, banks, and other parties.

 

In this blog, general overview of ER components will be covered, together with a tutorial presenting a way how to add financial dimension to an existing electronic report.

 

Electronic Reporting Components

 

Electronic reporting (ER) supports the following types of components:

 

  • Data model
  • Model mapping
  • Format
  • Metadata

Data Model Component


A data model component is an abstract representation of a data structure. It describes a specific business domain area in enough detail to satisfy the reporting requirements for that domain. A data model component consists of the following parts:

 

  • Data Model: A set of domain-specific business entities and a hierarchically structured definition of relations between those entities.

 

  • Model Mapping: Linking between individual elements of the data model and selected application data sources, specifying the data flow of the model itself.

 

The business entity of a data model is represented as a container, or record. Business entity properties are represented as data items, or fields. Each data item has a unique name, label, description, and value.

 

The value of each data item can be designed so that it’s recognized as a string, integer, real, date, enumeration (enum), or Boolean value. Additionally, the data item can be another record or record list.

 

Model Mapping Component

 

Model mapping links application data sources to individual elements of a data model that specify, at runtime, the data flow, and rules for entering business data in a data model component. It can use different data types as data sources for a data model.

 

These data types include tables, data entities, methods, and enums. It supports user input parameters that can be defined as data sources for a data model when some data must be specified at runtime (for example, which financial dimension to be included). Also filtering, sorting and other operations are supported, but only for outgoing documents.

 

Format Component

 

A format component is the scheme of the reporting output that is generated at runtime. A scheme consists of a format that defines the structure and content of the generated electronic document, data sources, format mapping as a set of bindings and a format validation as a set of configurable rules that control report generation at runtime.

 

For example, there might be a rule that stops output generation of a vendor’s payments and throws an exception when specific attributes of the selected vendor are missing, such as the bank account number.

 

Created reporting output can be as individuals file in various formats, such as text, XML, Microsoft Word document, or worksheet. But there is also a possibility of creating multiple files separately and encapsulating them into zip file. The following illustration shows how the data flows in outgoing report.

 

 

Problem Description

 

In France each company has to deliver so-called FEC report to the government. It is an export of several entities having a specific format. The format is very strict, that means when it is not correct, the declaration will not be approved.

 

The FEC report is available in F&O as part of the electronic reporting functionality, a localization made for France. However, the export of the ledger transactions is based upon the Main account.

 

In France you need a specific local chart of account. Imagine that this account is stored in a custom-made financial dimension called: FRACOA. The main goal is to replace main account values with FRACOA values.

 

To be more precise, the account number (CompteNum) should be replaced with the dimension’s value, while account description (CompteLib) should be replaced with the dimension’s description.

 

 

 

The report’s output format is a ZIP file containing 5 text
documents. Only the values in the first document called
1_FEC.txt need to be replaced. 

 

 

 

Solution

 

Because the ER already exists and it’s part of Microsoft standard configurations library, we do not want to create a new model, but rather to create a duplicate of the existing one. In that way, we can do modifications on it.

 

Modifications of an existing electronic report can be done only on a duplicated version of it. You are not allowed to change or modify existing standardized configurations.

 

 

The FEC report is located under the configuration named
‘Data export model’. As we can see, it consists of a model
definition, model mapping and two report designs (German
and French localization).

 

 

If you are missing the configuration for your report, then first you should go to Workspaces > Electronic reporting > from Configuration providers select Microsoft and click on Repositories > select Global and click Open > find the desired model and click Import/Import all (depending on if you would like to import everything or just particular configuration).

 

If we take a look at the design of the data model, we can see that it has quite a complex structure unlike ones that are usually used. Fields that will be included in the final report are rather dynamically structured and, in the model, we just define some fundamental nodes so they can fetch the data.

 

In this model, all fields are implicitly defined, contrary to most of the models where nodes (fields) are explicitly defined. The Tables node defines files from the zip, while in Records is defined the structure of records in one file.

 

If we expand one of the (*)Fields node, we can only see some type of rules to check what type is the value in the field, to cast it in the appropriate type and some additional metadata for the field.

 

 

This means that the model is pretty conserved and made to be generic. We do not need to change anything here. Thus, there is no need of duplicating the data model. Instead, we need to duplicate the model mapping and do our changes there.

 

Duplicating the Data Model Mapping

 

  • Make sure you are located in Workspaces > Electronic reporting > Reporting configurations > locate and expand the desired model in the tree, in our case it is ‘Data export model’

 

  • Select the model mapping, in our case it is ‘French FEC model mapping’ and click on Create configuration

 

  • In the drop dialog, for the New field select ‘Derive from Name: French FEC model mapping, Microsoft’. In the Name field, type the name for the mapping ‘AXM – French FEC model mapping’. In the Description field, you can set a description, but it is not mandatory. Click Create configuration.

 

Map the  Model to Use Financial Dimensions

 

  • In the tree, select the newly created model mapping ‘AXM – French FEC model mapping’ and click on Designer in the action pane.
  • Since we are creating a duplicate instead of new mapping, in the grid there should already be a record for the mapping – copy of the original one. Select it and click Designer.
  • In the Model mapping designer form, it can be seen that there are already some data sources defined. Those data sources are used for the current implementation of the report. First thing we need to do is to add the data source for using financial dimensions for this report.

 

  • In the tree, select ‘Functions\Financial dimensions details’ and click Add root. This data source specifies how the scope of financial dimensions will be defined for any report that will use this model as a data source.


  • In the Name field, type a value. Select Yes in the Ask for dimensions field (select Yes to allow the user to select dimensions at run-time on the User dialog form. If set to No, all financial dimensions of the current instance will be used by default).

 

  • In the Financial dimensions selection field, select ‘Legal entity’ (select All to allow the user to select desire dimensions for the current instance in the Lookup field. Select Legal entity to allow the user to select dimensions for the company in the Lookup field. Select Dimension to allow the user to select dimensions using a single dimension set.

 

  • Select Yes in the Ask for main account field (set ‘Ask for main account’ to Yes to allow users to select the main account as part of the list of dimensions. If set to No, the main account will not be included to the list of dimensions and the ‘Is main account mandatory’ option is enabled. If “Is main account mandatory’ is set to Yes, include the main account in the list of dimensions regardless of the user’s selection).

 

  • Click OK.

 

  • The newly created data source should be visible among other data sources in the middle section of the form.


 

  • If we take a closer look at data sources and data model, we can see that Tables node in the data model is bonded to the TblGroup data source. This data source is actually a calculated field that serves as a bridge between the model and the data source named TblGroup1. We need to find the source of data providing and in this case that is the data source ‘FEC files with details(TblGroup1)’. This data source is defined using specific function (Dynamics.AX.Application.ERModelGDPdUFunction). By expanding it, we cannot add fields or change mapping because its structure is generic too.



If you cannot see details about data sources binding and inheritance, click on Show details button in the main action pane.



 

  • Select FEC files with details(TblGroup1) and click on Edit button in the ribbon.

 

  • A new dialog will appear showing data source parameters. In addition, there is a button named Editor which allows us to enter the editing mode for making changes in the structure of the report. Click on Editor.


 

  • Table Metadata form is opened. This form is divided into three parts:

 

    • Tables (most left section) where all files are being present. In this grid the name of the table (file) is being shown together with a path relating to a particular data source.

 

    • Fields (middle section) where all fields related to a selected table from the left grid are being shown. In this grid, the name of the field is being shown together with a path relating to a particular node in a data source.

 

    • Data sources (right section) where all active data sources for the desired model are being shown. Above the grid, there is an Add button. Using this button, we can find the field we want in any active data source and add it in the desired table.





If you are not able to see all sections, zoom out the browser settings.

 

  • Select the desired table in the left section. In our case, because we need the change to be applied only to the 1_FEC.txt file, we select the table 1_FEC.

 

  • In the middle section, select fields you would like to replace. In this case, we select CompteNum and CompteLib. Click Delete.


 

  • In the right section, expand the general journal entry where financial dimensions are stored. In this case, we expand $GeneralJournalForGDPdUView data source. If you are not sure which data source to use, take the one that other fields from the same table are mapped from.

 

  • Expand and select ‘$GeneralJournalForGDPdUView/getGeneralJournalAccountEntry() /LedgerDimension.Dimension/Main account and dimensions/Value/Code’.

 

  • Click Add.


 

  • Expand and select ‘$GeneralJournalForGDPdUView/getGeneralJournalAccountEntry() /LedgerDimension.Dimension/Main account and dimensions/Value/Description’.

 

  • Click Add.

 

  • New fields should be visible somewhere in the grid, under their original names. Click on the Name field with value ‘Code’ and change it to ‘CompteNum’. Change the value ‘Description’ to ‘CompteLib’.

 

  • Using the Move up and Move down buttons, you can change the order of the fields in the grid. This is important because in same manner the fields will be shown in the output file.


  • Save the changes. Click Close.

 

  • Save the changes again and click Close.

 

  • From the configuration tree, select the desired model mapping, in this case it is ‘AXM – French FEC model mapping’. Select the Draft version and click Change status.

 

  • From the drop dialog, select Complete. If it’s the first time you are modifying the mapping. Now you will get two records in the gird, one that is Completed and one that is in Draft. After every change, if we want it to be reflected in the output, we need to set the latest draft version to Completed.

 

  • In order the report to take our custom-made mapping, we need to set it as default. This way, the system will know what mapping to choose when running the report. Make sure the correct mapping is still selected.

 

  • Click Edit and set the control Default model mapping to Yes.

 

Designing the Report

 

If we open the format designer to see the structure of the report, we can notice that it is generic, same as the model itself. This means that no changes need to be done here as well.

 

The advantage of using this approach for modeling reports is that the structure of the report is partially conserved, but if you do need to do some small changes, you only need to do changes into the mapping part.

 

 

Running the Report

 

Depending how this report is set to be ran in standard environment, you can test it from there, or you can navigate to the configurations form and:

 

  • Expand the model we created mapping for and select the format that already exists, in this case it is ‘French FEC audit file’ and click Run.

  • In the Dimensions field, choose which dimension you would like to be shown in the output report instead of the main account number and click Select (if FRACOA dimension is chosen, then we will get its values in the report, otherwise if the MainAccount is chosen, then we will obtain the original report from before.

 

  • This implementation gives flexibility in the way of execution. Note that the drop dialog to choose a dimension is not available in the original configuration of the report. This is customization that was implemented using this tutorial).

 

  • After clicking the OK button, a zip file is being generated and downloaded to the local computer. The downloaded zip file has a structure similar to this:




  • We can open the first text file and compare it with a previously downloaded version of the original report.

 

 

 

We can notice that the main account values are indeed replaced with FRACOA values for all entries. No changes were made to other 4 files so they will keep the same structure and data.

 

Following this tutorial, you should be able to do a modification on any report you need to. The most important thing is to understand the logic behind components of electronic reports and their binding. In a situation where the model and the format have explicit structure and mapping from data sources is done directly, creating the desired mapping has a little bit more work to be done. You just need to stick to the following sequence:

 

Create duplicate of a model > Create the node you would like to be shown in the output (make sure you create it under the correct parent node) > Create duplicate of the model mapping > If the data source where your field comes from is not present, create it > Bind the data source field and the newly created node in the model > Create a duplicate of the format and add the node there too > Map the node from the model with the node in the format.

 

No need to thanks us, we are glad to help you. So, if you are in need of someone to upgrade your systems from Microsoft Dynamics AX to Dynamics 365, we are open to future collaboration. Reach out to us here.

 

And if you are interested to be part of our team, check out our careers page we have open job vacancies all the time!

Application Insights with D365 F&O

What is Application Insights?

 

Application Insights, a feature of Azure Monitor, is an extensible Application Performance Management (APM) service for developers and DevOps professionals. Use it to monitor your live applications. It will automatically detect performance anomalies, and includes powerful analytics tools to help you diagnose issues and to understand what users do with your app.

 

It’s designed to help you continuously improve performance and usability. It works for apps on a wide variety of platforms including .NET, Node.js, Java, and Python hosted on-premises, hybrid, or any public cloud. It integrates with your DevOps process and has connection points to a variety of development tools. It can monitor and analyze telemetry from mobile apps by integrating with Visual Studio App Center.

 

 

Application Insights can be used to log:

 

  1. Events Azure Application Insights Telemetry Data Model – Event Telemetry – Azure Monitor | Microsoft Docs
  2. Exceptions Azure Application Insights Exception Telemetry Data model – Azure Monitor | Microsoft Docs
  3. Requests Data model for request telemetry – Azure Application Insights – Azure Monitor | Microsoft Docs
  4. Metrics Data model for metric telemetry – Azure Application Insights – Azure Monitor | Microsoft Docs
  5. Traces Azure Application Insights Data Model – Trace Telemetry – Azure Monitor | Microsoft Docs

 

How to create Application Insights Create Application Insights | Microsoft Docs

 

Something more about the Application insights Application Insights Overview | Microsoft Docs

 

How We Can Connect D365 with Azure Application Insights

 

Open your environment in the browser and navigate to the System Administration -> Setup -> Monitoring and telemetry parameters form.

 

 

From here, you can enable the different telemetry types that are currently supported. More will be added over time. Each type has the Dynamics terminology followed by the Application Insights terminology in parenthesis. This will help you know where to locate it in Application Insights as well as do further learning on docs.microsoft.com.

 

 

Setup your environments, by copying the LCS Environment ID into the setup screen and mapping it to an Environment Type:

 

 

Thereafter, you can map environment types to Application Insights destinations:

 

 

The instrumentation key is retrieved from your Application Insights resource within Azure

 

 

As you copy your Finance and Operations database between environments, it will instantly pick up the new Application Insights configuration and automatically send telemetry to the correct location. If you copy your database to an environment which is not configured, then the environment will gracefully do nothing, and no telemetry will be sent.

 

D365 Standard Class Used for Application Insights

 

  • SysGlobalTelemetry class has methods to log text to Azure Application Insights.

 

We can use these methods to log metrics for Interfaces to see for how much time the file is exported and uploaded to blob.

 

    • logMetrics() – Tracks how long, on average, a compute node takes to download the required text file.
    • logEvents() – Tracks interesting events to capture.
    • global_pre_error() – logs error.

 

Example:

 

 

Creating Custom C# dll

 

Application Insights is a very popular (and FREE) approach to monitoring your websites and desktop applications. It works best with websites hosted by IIS, however it can be built into any product.

 

Create a custom C# dll to implement the methods you need to consume the Microsoft.ApplicationInsights.dll to make it easier to use from X++.

 

The handler DLL will enable to:

 

  • Set context properties like user, operation, version & custom global properties;
  • Instance and track telemetry for Events, Exceptions, Requests, Metrics, Traces;
  • Add custom properties & custom metrics related with Events, Exceptions, Requests, Metrics, Traces.

 

Let’s start by building our own C# library which uses the latest NuGet package for AppInsights:

 

 

After you have your C# library setup and the NuGet package installed, we can start developing class that can handle our events.
Here is the example of the code from my C# class. This code is only to instance and track telemetry for Exceptions and Requests.

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.ApplicationInsights.DependencyCollector;
using Microsoft.ApplicationInsights.Web;

namespace AppInsightsHandler
{
    public class AppInsightsHandler
    {
        
        private TelemetryClient 	Client;

        private RequestTelemetry 	requestTelemetry;
        private ExceptionTelemetry 	exceptionTelemetry;

        string objectType;

        List<KeyValuePair<string, string>> properties = new List<KeyValuePair<string, string>>();
        List<KeyValuePair<string, string>> ContextGlobalProperties = new List<KeyValuePair<string, string>>();
        List<KeyValuePair<string, Double>> metrics = new List<KeyValuePair<string, Double>>();

        public void instantiateClient(string _instrumentationKey, string _objectType)
        {

            if (string.IsNullOrEmpty(_instrumentationKey))
            {
                throw new ArgumentNullException(nameof(_instrumentationKey), "Instrumentation key is required.");
            }
            if (string.IsNullOrEmpty(_objectType))
            {
                throw new ArgumentNullException(nameof(_objectType), "Object type is required.");
            }
            objectType = _objectType;
            TelemetryConfiguration config = new TelemetryConfiguration(_instrumentationKey);
            Client = new TelemetryClient(config);
            switch (objectType)
            {
                case "ExceptionTelemetry":
                    exceptionTelemetry = new ExceptionTelemetry();
                    break;
                case "RequestTelemetry":
                    requestTelemetry = new RequestTelemetry();
                    break;
            }

        }

        public void addProperty(string _key, string _value)
        {
            KeyValuePair<string, string> property = new KeyValuePair<string, string>(_key, _value);
            if (!properties.Exists(item => item.Key == _key))
            {
                properties.Add(property);
            }
        }

        public void addContextGlobalProperty(string _key, string _value)
        {
            KeyValuePair<string, string> property = new KeyValuePair<string, string>(_key, _value);
            if (!ContextGlobalProperties.Exists(item => item.Key == _key))
            {
                ContextGlobalProperties.Add(property);
            }
        }
        public void addMetrics(string _key, Double _value)
        {
            KeyValuePair<string, Double> metric = new KeyValuePair<string, Double>(_key, _value);
            if (!metrics.Exists(item => item.Key == _key))
            {
                metrics.Add(metric);
            }
        }

        public void setContextUserInfo(string _accountId, string _authenticatedUserId, string _userId = "", string _userAgent = "")
        {
            switch (objectType)
            {
                case "ExceptionTelemetry":
                    exceptionTelemetry.Context.User.AccountId = _accountId;
                    exceptionTelemetry.Context.User.AuthenticatedUserId = _authenticatedUserId;
                    exceptionTelemetry.Context.User.Id = _userId;
                    exceptionTelemetry.Context.User.UserAgent = _userAgent;
                    break;
                case "RequestTelemetry":
                    requestTelemetry.Context.User.AccountId = _accountId;
                    requestTelemetry.Context.User.AuthenticatedUserId = _authenticatedUserId;
                    requestTelemetry.Context.User.Id = _userId;
                    requestTelemetry.Context.User.UserAgent = _userAgent;
                    break;
            }
        }
        public void setContextOperation(string _operationId, string _operationName, string _parentId = "")
        {
            switch (objectType)
            {
                case "ExceptionTelemetry":
                    exceptionTelemetry.Context.Operation.Id = _operationId;
                    exceptionTelemetry.Context.Operation.Name = _operationName;
                    exceptionTelemetry.Context.Operation.ParentId = _parentId;
                    break;
                case "RequestTelemetry":
                    requestTelemetry.Context.Operation.Id = _operationId;
                    requestTelemetry.Context.Operation.Name = _operationName;
                    requestTelemetry.Context.Operation.ParentId = _parentId;
                    break;
            }
        }
        public void setContextComponentVersion(string _version)
        {
            switch (objectType)
            {
                case "ExceptionTelemetry":
                    exceptionTelemetry.Context.Component.Version = _version;
                    break;
                case "RequestTelemetry":
                    requestTelemetry.Context.Component.Version = _version;
                    break;
            }
        }

        public void setContextGlobalProperties()
        {
            foreach (KeyValuePair<string, string> element in ContextGlobalProperties)
            {
                
                switch (objectType)
                {
                    case "ExceptionTelemetry":
                        exceptionTelemetry.Context.GlobalProperties.Add(element);
                        break;
                    case "RequestTelemetry":
                        requestTelemetry.Context.GlobalProperties.Add(element);
                        break;
                }
            }
        }
       
        public void setsysExceptionTelemetryValues(Exception _exception, string _message, string _problemId, int _severityLevel)
        {
            if (exceptionTelemetry != null)
            {

                exceptionTelemetry.Exception = _exception;
                exceptionTelemetry.Message = _message;
                exceptionTelemetry.ProblemId = _problemId;
                switch (_severityLevel)
                {
                    case 4:
                        exceptionTelemetry.SeverityLevel = SeverityLevel.Critical;
                        break;
                    default:
                        exceptionTelemetry.SeverityLevel = SeverityLevel.Information;
                        break;
                }
                exceptionTelemetry.Timestamp = DateTimeOffset.UtcNow;
                foreach (KeyValuePair<string, string> element in properties)
                {
                    exceptionTelemetry.Properties.Add(element);
                }
                foreach (KeyValuePair<string, Double> element in metrics)
                {
                    exceptionTelemetry.Metrics.Add(element);
                }

            }
        }
  public void TrackTelemetry()
        {
            if (Client != null && objectType != "")
            {
                switch (objectType)
                {
                    case "ExceptionTelemetry":
                        Client.TrackException(exceptionTelemetry);
                        break;
                    case "RequestTelemetry":
                        Client.TrackRequest(requestTelemetry);
                        break;
                }
                Client.Flush();
            }
        }
        public void setExceptionTelemetryValues(string _exceptionMessage, string _exceptionSource, string _message, string _problemId, int _severityLevel)
        {
            if (exceptionTelemetry != null)
            {
                Exception e = new Exception(_exceptionMessage);
                e.Source = _exceptionSource;
                exceptionTelemetry.Exception = e;
                exceptionTelemetry.Message = _message;
                exceptionTelemetry.ProblemId = _problemId;
                switch (_severityLevel)
                {
                    case 0:
                        exceptionTelemetry.SeverityLevel = SeverityLevel.Verbose;
                        break;
                    case 1:
                        exceptionTelemetry.SeverityLevel = SeverityLevel.Information;
                        break;
                    case 2:
                        exceptionTelemetry.SeverityLevel = SeverityLevel.Warning;
                        break;
                    case 3:
                        exceptionTelemetry.SeverityLevel = SeverityLevel.Error;
                        break;
                    case 4:
                        exceptionTelemetry.SeverityLevel = SeverityLevel.Critical;
                        break;
                    default:
                        exceptionTelemetry.SeverityLevel = SeverityLevel.Information;
                        break;
                }
                exceptionTelemetry.Timestamp = DateTimeOffset.UtcNow;
                foreach (KeyValuePair<string, string> element in properties)
                {
                    exceptionTelemetry.Properties.Add(element);
                }
                foreach (KeyValuePair<string, Double> element in metrics)
                {
                    exceptionTelemetry.Metrics.Add(element);
                }

            }
        }
    
        public void setRequestTelemetryValues(string _requestName, string _requestId, Boolean _success, string _responseCode, string _source, string _uriString, Double _duration)
        {
            if (requestTelemetry != null)
            {
                requestTelemetry.Name = _requestName;
                requestTelemetry.Timestamp = DateTimeOffset.UtcNow;
                requestTelemetry.Success = _success;
                requestTelemetry.Id = _requestId;
                requestTelemetry.ResponseCode = _responseCode;
                requestTelemetry.Source = _source;
                requestTelemetry.Duration = TimeSpan.FromSeconds(_duration);
                if (_uriString != "")
                {
                    Uri uri = new Uri(_uriString);
                    requestTelemetry.Url = uri;
                }

                foreach (KeyValuePair<string, string> element in properties)
                {
                    requestTelemetry.Properties.Add(element);
                }
                foreach (KeyValuePair<string, Double> element in metrics)
                {
                    requestTelemetry.Metrics.Add(element);
                }
            }
        }

    }
}

 

After that create an X++ project in your solution and add a reference to your C# library:

 

 

Thereafter, let’s create an X++ class which makes use of our telemetry library:

 

 

Let us know if this helped you, and if you are interested to work with Microsoft Dynamics 365 you can check out our careers page for the open job positions. 

 

Processing an Excel File in Batch Using the FileUpload Functionality Together with SysOperationFramework

Sometimes in D365 things happen which are either human or system error, which will leave you with faulty data in your system.

 

That kind of thing happened some time ago for one of our clients, when a daily batch job removed all the loads for the purchase orders which had lines who have ‘Registered’ quantities, and left them with more than 3000 purchase orders for which they couldn’t create and post a product receipt journal, because they didn’t have the load associated with them, and going with the logic of creating a new batch job for posting product receipts for quantity = ‘Registered’ would’ve broke their workflow.

 

So, they exported the purchase orders that they wanted to update, and after seeing that the update should be done for more than 3000 orders, I knew that I should extend the SysOperationFramework, so the update could be done in batch processing on the server, and the users wouldn’t experience any performance issues on the interface itself.

 

When talking about extending the SysOperationFramework parts, you probably already know that we will have the well-known structure of classes in order to design our batch process: the controller class, responsible for running the operation and modifying the contract, the contract class, responsible for passing parameters and values from the user to the logic that processes operation, the service class, responsible for providing the logic which is being executed (in our example, iterating through the Excel file, getting the purchase orders IDs and posting a product receipt for them), and the User Interface builder (UIBuilder) class, responsible for the actual looks and event handlers of the dialog that is presented to the user.

 

Let’s have a look at what our code changes will look like in the D365 user interface, before scheduling the actual batch job:

 

 

Analyzing this dialog, we will see that it looks like every other batch dialog, with only one parameter: a file.

 

Below, we will see the code which is taking care of the design and functionality for this batch process.

 

The Controller Class:

 

/// <summary>
/// Controller class for creating & posting PO packing slips
/// </summary>
class AXMPostPOReceiptsController extends SysOperationServiceController
{
	/// <summary>
    /// Creates new instance of <c>AXMPostPOReceiptsController</c>
    /// </summary>
    public void new()
    {
        super();
     
        this.parmClassName(classStr(AXMPostPOReceiptsService));
        this.parmMethodName(methodStr(AXMPostPOReceiptsService, processOperation));
     
        this.parmDialogCaption("Create packing slips");
    }
	
	/// <summary>
    /// Sets the caption of the job
    /// </summary>
    /// <returns>Caption of the job</returns>
    public ClassDescription caption()
    {
        return "Create packing slips";
    }
	
	/// <summary>
    /// Method which is run while calling the corresponding menu item
    /// </summary>
    /// <param name = "args">Arguments passed from the menu item</param>
    public static void main(Args args)
    {
        AXMPostPOReceiptsController controller;
     
        controller = new AXMPostPOReceiptsController();
        controller.startOperation();
    }
}

 

Looking at the code for the AXMPostPOReceiptsController, we see that it has 3 methods, of which 2 are overridden: new and caption. Above every method there is a summary explanation of what that method is doing. We can see that in the new method, we are initializing a new instance of the controller class and are defining the processing class and method (the service class), in our case, AXMPostPOReceiptsService class.

 

Please don’t be confused about the caption and the dialog caption for the batch job, ‘Create packing slips’, we know that sometimes we also refer to the product receipts as packing slips.

 

The Data Contract Class:

 

/// <summary>
/// Data contract class for creating & posting PO packing slips
/// </summary>
[   DataContract,
    SysOperationContractProcessing(classStr(AXMPostPOReceiptsUIBuilder))
]
class AXMPostPOReceiptsDataContract
{
    container       storageResult;

	/// <summary>
    /// Parameter method which holds values of the packed variables from <c>FileUploadTemporaryStorageResult</c> class
    /// </summary>
    /// <param name = "_storageResult">Packed instance of <c>FileUploadTemporaryStorageResult</c> class</param>
    /// <returns>Container with packed values</returns>
    [DataMemberAttribute('StorageResult')]
    public container parmStorageResult(container _storageResult =  storageResult)
    {
        storageResult = _storageResult;
        return storageResult;
    }
}
    

 

As said, the data contract class holds the parameters that user wants to pass to the logic which is being executed. In our case, we have one parameter that we’re passing, storageResult of type container. As explained in the summary, this variable holds the values of the packed variables of the FileUploadTemporaryStorageResult class instance, which in fact holds the upload result of the FileUpload control.

 

As for now, the only thing that you need to know is that FileUploadTemporaryStorageResult implements SysPackable, which means that we can do serialization on it, like pack and unpack the variables defined in the #CurrentList for the #CurrentVersion macro.

 

Note: Please visit the File upload control page, where you can find documentation on this control.

 

The UI Builder Class:

 

/// <summary>
/// UI Builder class for posting purchase orders packing slips
/// </summary>
class AXMPostPOReceiptsUIBuilder extends SysOperationUIBuilder
{
    private str                 availableTypes = ".csv, .xlsx";
    private const str           OkButtonName = 'CommandButton';
    private const str           FileUploadName = 'FileUpload';
	
    AXMPostPOReceiptsDataContract   contract;

	/// <summary>
    /// Overriden the <c>postBuild</c> method to add a <c>FileUpload</c> control
    /// </summary>
    public void postBuild()
    {
        DialogGroup      dialogGroup;
        FormBuildControl formBuildControl;
        FileUploadBuild  dialogFileUpload;

        super();

        contract = this.dataContractObject();
        
        dialogGroup = dialog.addGroup("File path");
        formBuildControl = dialog.formBuildDesign().control(dialogGroup.name());
       
        dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), FileUploadName);
        dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
        dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
        dialogFileUpload.fileTypesAccepted(availableTypes);
        dialogFileUpload.fileNameLabel("@SYS308842");
    }

	/// <summary>
    /// Subscribes events to the dialog form
    /// </summary>
    /// <param name = "_formRun">The instance of the dialog form</param>
    private void dialogEventsSubscribe(FormRun _formRun)
    {
        FileUpload fileUpload = _formRun.control(_formRun.controlId(FileUploadName));
        fileUpload.notifyUploadCompleted += eventhandler(this.uploadCompleted);
        fileUpload.notifyUploadAttemptStarted += eventhandler(this.uploadStarted);
        _formRun.onClosing += eventhandler(this.dialogClosing);
    }
	
	/// <summary>
    /// Executes logic for unsubscribing the registered events on the form
    /// </summary>
    /// <param name = "sender"></param>
    /// <param name = "e"></param>
    [SuppressBPWarningAttribute('BPParameterNotUsed', 'This is event parameter not required to use')]
    private void dialogClosing(xFormRun sender, FormEventArgs e)
    {
        this.dialogEventsUnsubscribe(sender as FormRun);
    }
	
	/// <summary>
    /// Unsubscribes events from the dialog form
    /// </summary>
    /// <param name = "_formRun">The instance of the dialog form</param>
    private void dialogEventsUnsubscribe(FormRun _formRun)
    {
        FileUpload fileUpload = _formRun.control(_formRun.controlId(FileUploadName));
        fileUpload.notifyUploadCompleted -= eventhandler(this.uploadCompleted);
        fileUpload.notifyUploadAttemptStarted -= eventhandler(this.uploadStarted);
        _formRun.onClosing -= eventhandler(this.dialogClosing);
    }
	
    /// <summary>
    /// Executes additional logic once the upload of the file is completed
    /// </summary>
    protected void uploadCompleted()
    {
        var formRun = this.dialog().dialogForm().formRun();
        FileUpload fileUpload = formRun.control(formRun.controlId(FileUploadName));
        FileUploadTemporaryStorageResult uploadResult = fileUpload.getFileUploadResult();

        if (uploadResult != null && uploadResult.getUploadStatus())
        {
            contract.parmStorageResult(uploadResult.pack());
        }

        this.setDialogOkButtonEnabled(formRun, true);
    }
	
	/// <summary>
    /// Additional logic which is executed once the upload of the file has started
    /// </summary>
    private void uploadStarted()
    {
        var formRun = this.dialog().dialogForm().formRun();
        this.setDialogOkButtonEnabled(formRun, false);
    }

    /// <summary>
    /// Enables/Disables the OK button of the dialog
    /// </summary>
    /// <param name = "_formRun">The instance of the dialog form</param>
    /// <param name = "_isEnabled">Should the OK button be enabled?</param>
    protected void setDialogOkButtonEnabled(FormRun _formRun, boolean _isEnabled)
    {
        FormControl okButtonControl = _formRun.control(_formRun.controlId(OkButtonName));
        if (okButtonControl)
        {
            okButtonControl.enabled(_isEnabled);
        }
    }

    /// <summary>
    /// Override of the <c>postRun</c> method in order to add events subscriptions
    /// </summary>
    public void postRun()
    {
        super();

        FormRun formRun = this.dialog().dialogForm().formRun();
        this.dialogEventsSubscribe(formRun);

        this.setDialogOkButtonEnabled(formRun, false);
    }

}

    

We can see that in this class we have more methods and more logic. You can also notice that we have event handlers, which should run the specified code once the event is started or completed. Analyzing the code, first we can see that the method postBuild has been overridden. Here, we’re constructing the actual look of the dialog. We can see that first we’re creating a group for the file path, and after that we’re adding the FileUpload control, we’re setting the style and the file upload strategy (you can see the documentation in the referenced documentation for File upload). We can also set the available types that user will be able to choose and upload. You can see that the availableTypes is actually string variable with file extensions defined.

 

After we’re done with adding controls to the dialog, it’s time to make the form responsive, and that’s when the event handlers come into action. As for every event, first we need to do a subscription to a certain event, and after we’re finished, we unsubscribe from that event. So, next we will have a look at method postRun which is called once the dialog is built and ran.

 

In this method, we see that we’re taking instance of the current dialog (FormRun), we’re making event subscriptions for that FormRun instance and we’re calling the method setDialogOkButtonEnabled which as the name suggests, it’s either enabling/disabling the ‘OK’ button, which is actually submitting the form displayed on the dialog. The solution here is only enabling the ‘OK’ button once we have successfully uploaded a file.

 

Now, let’s review the logic for subscribing and unsubscribing to an event. Looking at method dialogEventsSubscribe, we see that we’re retrieving the FileUpload control that we’ve created in postBuild method, and we’re adding (subscribing) to events for once the upload has attempted to start and once the upload is completed. The event handlers for these events are respectively methods uploadStarted and uploadCompleted. After that, we’re assigning an event handler for the onClosing event of the FormRun, which is basically calling another method, dialogEventsUnsubscribe, which is basically subtracting (unsubscribing) the event handlers from the events.

 

Looking at the event handlers, we can see that event handler uploadStarted doesn’t do anything special, but only disables the dialog ‘OK’ button. However, the other event handler, uploadCompleted, we’re once again retrieving the FileUpload, but this time, because the upload is completed, it means that we can take the upload result and store it somewhere (or do additional logic with it).

 

After taking the result of the file upload, as explained before, I am packing the result and sending it as a parameter to our contract class, so I can later use it in our service class, where all the logic for creating and posting the product receipts is located.

 

The Service Class

 

/// <summary>
/// Service class which is executing the logic for creating & posting PO packing slips
/// </summary>
class AXMPostPOReceiptsService extends SysOperationServiceBase
{
    #File
    container               currentLine;
    CommaTextStreamIo       localStream;
    PurchId                 currentPurchId;
    PurchTable              purchTable;

    /// <summary>
    /// The actual logic of the process
    /// </summary>
    /// <param name = "_contract">Instance of the <c>AXMPostPOReceiptsDataContract</c> class</param>
    public void processOperation(AXMPostPOReceiptsDataContract _contract)
    {
        if (_contract.parmStorageResult() != conNull())
        {
            FileUploadTemporaryStorageResult fileUploadResult = new FileUploadTemporaryStorageResult();

            fileUploadResult.unpack(_contract.parmStorageResult());

            if (fileUploadResult != null)
            {
                try 
                {
                    localStream = CommaTextStreamIo::constructForRead(File::UseFileFromURL(fileUploadResult.getDownloadUrl()));

                    if (localStream.status() != IO_Status::Ok)
                    {
                        throw error(strfmt('Is not possible to open the file. Error %1',enum2str(localStream.status())));
                    }
   
                    localStream.inFieldDelimiter("\,");
                    localStream.inRecordDelimiter("\n");
   
                    currentLine = localStream.read();
   
                    while(currentLine)
                    {
                        currentPurchId = conPeek(currentLine, 1);

                        purchTable = PurchTable::find(currentPurchId);

                        if (purchTable)
                        {
                            Num psNumber = strFmt("%1_PS", currentPurchId);

                            PurchFormLetter     purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);
                            purchFormLetter.update(purchTable, psNumber, systemDateGet(), PurchUpdate::Recorded, AccountOrder::None, NoYes::No, NoYes::No);
                        }
            
                        currentLine = localStream.read();
                    }
                }
                catch (Exception::Error)
                {
                    error("@RET433");
                }
            }
        }
    }
}

 

Since we’re only doing a creation and posting of a product receipt for a certain purchase orders, the logic here will be pretty simple. We can see that we have once method, processOperation, which is taking an instance of the data contract class. With the help of the data contract, we can transfer the packed values of the file upload result from the UI builder to the service class.

 

Once we have unpacked the result, we’re constructing an IO stream, to which we’re using a file from URL, and that URL is generated with the help of FileUploadTemporaryStorageResult based on the unpacked values. I have wrapped all of the logic in try – catch block, and the code iterates trough the file that the user has uploaded previously, and it’s getting column values (in my case, it’s getting only the values from the first column, since I don’t have additional columns).

 

Once the value is taking, code is checking whether a purchase order exists for that purchase ID, and if it does, it proceeds with creating and posting the product receipt with the help of the PurchFormLetter class, and as you can see the parameters for the update are a buffer of the purchase table, a number for the packing slip (which in this case is generated manually, but that can be done via number sequences too), the date of the posting, the update parameter (in this case, only ‘Registered’ lines will be included), the account order set to ‘None’, and the settings for the proforma and whether the packing slip should be printed or not (both options set to ‘No’).

 

This was everything for processing a file in batch using the SysOperationFramework that you should know for starters. I really hope that I have well explained the bits of code which were presented.

 

Please note that there is also another way to solve this, and that would be to create a data entity and a table in which you will place your values (for this example, purchase order IDs), and also a batch classes and a query against the newly created table, so you can process the data that you have implemented. Both solutions work well, and although the data entity solution is more extendible, the one with the file upload is quicker and less painful.

Data Upgrade from Microsoft Dynamics AX2012 R2 / AX2012 R3 to Dynamics 365 for Finance and Operations

Upgrading Microsoft Dynamics AX2012 to Dynamics 365 Finance and Operations brings the digital transformation in most companies by giving them the ability to use significant new features and capabilities.

 

Recently, we have added another successfully completed data upgrade project for one of our clients in our portfolio. If you are looking for some help while upgrading from AX2012 R2 or Ax 2012 R3 to Dynamics 365 then you are at the right place.

 

This process contains several phases:

 

  • Preparing the database in the AX2012 environment
  • Installing a deployable package on the D365 development environment
  • Migrating upgraded database from D365 one-box to sandbox environment

 

 

 

AX2012 Procedure

 

The process starts in the AX 2012 environment where you have to prepare the ax2012 database for upgrading to Dynamics 365. Microsoft has put together a pre-upgrade checklist that has to be installed in Dynamics AX 2012. The checklist ensures you have updated information in your database for the AX 2012 to D365 upgrade.

 

 

After the installation of the hotfix, run the sysCheckList classes to prepare the database. After executing the process in the AX2012 environment we must make a backup from this database and transfer it to the D365 development environment. For transferring databases between environments, we will use Microsoft Azure Storage.

 

D365 Procedure

 

Most of the errors must be resolved in this process while installing the data upgrade deployable package.

 

The process on D365 development environment is following:

 

  1. Restore and rename the database.
  2. Install deployable package.
  3. Made another back up from this database and restore it to prepare it for Tier2 environment.
  4. Export a bacpac file for transferring

 

 

Restore the Database

 

After restoring the database on D365 environment we need to rename the names of the databases. Rename the original AxDB to AxDB_Orig and then rename the newly restored database to AxDB.

 

Install a Deployable Package

 

Download data upgrade deployable package from Shared asset library from Software deployable package, find the data upgrade package that corresponds to your upgrade.

 

If you’re upgrading from AX 2012, the package name starts with AX2012DataUpgrade-x-x-x where x-x-x is the application release. Select the package that corresponds to the release you are upgrading to. After downloading extract it and install it.

 

Make a Back-up to Prepare the Database for Tier 2

 

After the installation of the deployable package completes, we need to make back up from this database and restore it again in this environment. We will do this because we will delete some objects from it to prepare for the sandbox environment.

 

Do the following steps in SQL management studio against the newly imported database:

 

  • Update sysglobalconfiguration table

 

  • Drop procedure XU_DisableEnableNonClusteredIndexes and drop following users: axdbadminaxdeployuseraxmrruntimeuseraxretaildatasyncuseraxretailruntimeuser

 

  • remove NT users as these are not supported in Azure SQL Database

 

  • remove any AX 2012 RTM model store procedures that still exist

 

  • If you receive a message that you cannot delete users because they own a schema, then check which schema the user owns. Either change the ownership to another user (for example to do) or drop the schema if it does not contain any objects.

 

  • drop all views in the current database because some refresh the tempDB, which is not a supported action in Azure SQL Databases

 

  • Drop MaintainShipCarrierRole procedure because it contains a tempDB reference that is not supported in Azure SQL Database

 

  • Export a bacpac file for transferring 

 

After all this, the last step on the development environment is to export a bacpac file that should be imported in a sandbox environment. Go to the following location and execute the following command for exporting the file

 

A Process on the D365 Sandbox Environment

 

After transferring the database, we need to do the following steps:

 

  • Import the database;
  • Create users and prepare the database;
  • Rename the database;
  • Full database synchronization.

 

Import the Database

 

Import the database into the sandbox environment.

 

Create Users on the Newly Imported Database

 

Create users that were dropped in the preparation procedure. The passwords for the users must be copied from the LCS from the environment where we are importing the database. After users are created, alter the database with the required configuration.

 

Rename the Database

 

Full Database Synchronization  

 

Run full database synchronization and after it completes successfully you are ready to use the environment.

 

If you are interested in optimizing/improving your business processes, making the experience while using the application a whole lot easier in the long run, having the data secured in the cloud at the same time, and in need for someone to upgrade your systems from Microsoft Dynamics AX to Dynamics 365, we are open for future collaboration.

 

Reach out to us here, and if you are interested in potential career opportunities, check out our careers page.

Microsoft Dynamics 365 Applications – What’s New

More and more companies, especially now given the state of the world, opt for digital transformations in many sectors of their businesses. Microsoft has followed this movement every step of the way of providing its clients with customizable solutions to best suit any businesses and their needs.

 

Thanks to the variety of available solutions for digital transformation fit for financial services, retail, healthcare, and much more, Microsoft has been able to help its clients adjust seamlessly to the ever-growing technological demands that arise.

 

On this topic, you may come across new and recently updated Microsoft Dynamics 365 suite.

 

Microsoft Dynamics 365 Applications

 

Microsoft Dynamics 365 is a total business software package, ERP, and CRM solutions, comprised of multiple applications. Applications offered are Sales, Customer Service, Field Service, Human Resources, Finance, Project Operations, Supply Chain Management,  Commerce, Project Service Automation, Marketing, and Business Central.

 

What is important to note here from the aforementioned is the news regarding splitting Dynamics 365 for Finance and Operations in new separated applications that covers parts of the business functionalities that offer one ERP system.

 

What was formerly known as Dynamics 365 Finance and Operations has now been split into separate applications and with that, we now have Dynamics 365 Finance, Dynamics 365 Supply Chain Management, Dynamics 365 Project Operations, Dynamics 365 Commerce, and Dynamics 365 Human Resources. This change was made in order to offer greater flexibility to the users to apply the applications per their business processes’ needs.

 

Let make a quick overview of what the new applications offer to the Microsoft Dynamics 365 community.

 

Dynamics 365 Finance

 

Dynamics 365 Finance is the application used to simplify and automate global financial operations. This is the only solution you will need for all financial plans and decisions.

 

With Finance, all company expenses can be automated, saving on time and manpower. Automated financials results in greater control over regular expenses, cash flow, budgeting, and much more.

 

In addition, coming soon there will be Finance Insights with which predictions of financial success would become much easier and more accurate.

 

 

  • Increased awareness of company-wide finances with real-time analytics;

 

  • Taking advantage of AI with machine learning, predictive recommendations ensures an increase in profits and simplifies decision making;

 

  • Simplified financial planning and budget control with financial process automation;

 

  • Ensured compliance with local (and global) financial and business requirements with customizable payment, tax, and reporting formats.

 

Dynamics 365 Supply Chain Management

 

Dynamics 365 Supply Chain Management is the new application used to streamline all company operations from production to transportation and more.

 

Apart from automation of supply of stock, with which overstocking or lack of stock can be avoided, with Supply Chain Management you can modernize warehouse management as well as prolong the life of equipment with regularly scheduled maintenance aided by IoT and mixed reality.

 

 

  • A greater understanding of warehousing capacity, shipping operations, and turnover of materials in real-time;

 

  • Improvement of manufacturing operations and delivery processes by using machine learning and increase the productivity of people, processes, and equipment with mixed reality;

 

  • Ensured timely availability of necessary materials and products on designated locations with automatization of supply chain operations;

 

  • Increased product quality with integrated quality-control.

 

Dynamics 365 Commerce

 

Dynamics 365 Commerce, formerly known as Retail, offers its users a full omnichannel solution that unifies back-office, in-store, call center, and digital experiences.

 

With Commerce, retailers can forge a stronger connection and have a better understanding of their customers’ needs. With this solution, online stores work seamlessly on any device.

 

 

  • Ability to engage with customers at any stage and have access to a comprehensible view of every client;

 

  • Highly scalable to fit the specific needs of e-commerce;

 

  • Simplify the creation of interesting and intelligent storefronts with easy-to-use development tools;

 

  • Maximize profits and customer loyalty by using all AI has to offer, from targeted recommendations to insights.

 

Dynamics 365 Human Resources

 

Dynamics 365 Human Resources is an application for people. Any company that cares for its employees wants to make their day to day office life simpler so they can focus on more important things.

 

With this solution, all HR-related questions are easily accessible to the employees through self-service tools. HR management has never been so simple as this app can be easily tailored to fit companies of any size and help them simplify and organize all HR programs such as compensation, benefits, absence, and more.

 

 

  • Keep track of employee KPIs, certifications, training, and skills by creating detailed employee profiles;

 

  • Very adaptable allowing any company, whatever size or vocation, to successfully scale, extend, and connect to existing systems;

 

  • Ability to optimize HR programs by simplifying absence reporting, optimizing benefits, managing recruiting, and much more.

 

Dynamics 365 Project Operations

 

Dynamics 365 Project Operations is the latest release and it’s set to be available in October of 2020. Project functionality that used to come native to Dynamics 365 Finance and Dynamics 365 — Project Service Automation will now be merged and available as Dynamics 365 Project Operations.

 

Businesses that work with project-based services know that this is cooperative work. Dynamics 365 Project Operations was created with this in mind, so the goal is to unify operational workflows within a single application for increased productivity and timely project delivery.

 

 

  • Greater visibility for better collaboration between previously disconnected systems with the goal of precise tracking of project expenses, delivery dates, timely billing, and more;

 

  • Supply teams with the right insights to better understand every step made with visibility into the back-end and front-end processes of the same application;

 

  • Faster client billing and reimbursement with simplified processes of reporting time and expenses.

 

These are only a few of the capabilities of these new applications. Now as Microsoft keeps up to date with the needs of its users, so do we. As a Gold Partner specialized in delivering Microsoft Dynamics 365 services that cover the ERP part of the suit, we keep up with the latest Microsoft updates and help our clients to adapt more easily.

 

The developers and consultants here at Axapta Masters are skilled at these new applications and up to the task of assisting our clients as they begin to integrate them for themselves.

 

If you are interested in our services, or you have an idea of how can we help, feel free to drop us a line in the Contact section.