Tag Archive for: Dynamics 365 Sales

In this blog post, I’ll show you how to create a solution in Dynamics 365 that automatically ensures the Opportunity currency matches the Account currency.

I wrote this solution as I got so frustrated that when you create an opportunity in Dynamics 365 Sales, that the currency is not automatically set to the correct currency. Instead it goes to the default currency as set in the system, which will create all sort of problems when you are working in a multi region sales team. (selection of wrong currencies, quote then cannot use the correct currency, etc)

This solution will use JavaScript to retrieve and compare these values, and if they don’t match, update the Opportunity currency to reflect the Account’s currency. Additionally, we’ll publish this solution and configure it to run seamlessly within Dynamics 365.

Prerequisites

Before you begin, ensure you have the following:

  • Administrator access to Dynamics 365.
  • Basic understanding of JavaScript and Dynamics 365 customization.

Let’s break down the process step-by-step.

Step 1: Create a New Solution in Dynamics 365

The first step is to create a solution to contain your custom JavaScript logic and publish it into Dynamics.

  1. Navigate to Power Platform Admin Center:
    • Go to your Dynamics 365 environment.
    • Click on the gear icon and select Advanced Settings.
    • In the settings area, click on Solutions.
  2. Create a New Solution:
    • Click New to create a new solution.
    • Enter details such as:
      • Display Name: Opportunity-Account Currency Sync.
      • Publisher: Select or create a new one.
      • Version: Start with 1.0.0.0.
  3. Add the Opportunity Entity to the Solution:
    • In the solution editor, click on Add ExistingEntityOpportunity.
    • This allows us to add custom logic to the Opportunity entity form.

Step 2: Write the JavaScript for Currency Sync

Next, we’ll write the JavaScript code to compare the Opportunity and Account currency and update the Opportunity currency if they don’t match.

  1. Create a Web Resource for JavaScript:
    • In the solution, navigate to Web Resources and click New.
    • Select JavaScript (JScript) as the type, and name it currencySync.js.
    • Paste the following JavaScript code into the web resource:
    • function getDetailsFromOpportunity(executionContext) {
      var formContext = executionContext.getFormContext();
      
      // Check if the Opportunity has been saved (i.e., it has an ID)
      var opportunityId = formContext.data.entity.getId();
      if (!opportunityId) {
      console.log("This is a new opportunity. The record has not been saved yet.");
      return; // Exit the function if it's a new, unsaved Opportunity
      }
      
      // Proceed with the currency check if the Opportunity is not new
      opportunityId = opportunityId.replace("{", "").replace("}", "");
      
      // Get the Account (Customer Field) from the Opportunity
      var accountLookup = formContext.getAttribute("parentaccountid"); 
      if (accountLookup != null && accountLookup.getValue() != null) {
      var account = accountLookup.getValue()[0]; 
      var accountId = account.id;
      
      // Retrieve the statuscode and compare currencies only if the opportunity is open
      Xrm.WebApi.retrieveRecord("opportunity", opportunityId, "?$select=statuscode").then(
      function success(result) {
      var opportunityStatus = result.statuscode; 
      if (opportunityStatus === 1) { 
      console.log("Opportunity is open. Proceeding with currency check.");
      
      // Retrieve the currency from the related Account
      Xrm.WebApi.retrieveRecord("account", accountId, "?$select=transactioncurrencyid&$expand=transactioncurrencyid($select=currencyname)").then(
      function success(result) {
      if (result.transactioncurrencyid != null) {
      var accountCurrencyId = result.transactioncurrencyid.transactioncurrencyid.toLowerCase(); 
      
      // Get the Currency field from the Opportunity
      var opportunityCurrencyLookup = formContext.getAttribute("transactioncurrencyid"); 
      if (opportunityCurrencyLookup != null && opportunityCurrencyLookup.getValue() != null) {
      var opportunityCurrency = opportunityCurrencyLookup.getValue()[0]; 
      var opportunityCurrencyId = opportunityCurrency.id.replace("{", "").replace("}", "").toLowerCase(); 
      var opportunityCurrencyName = opportunityCurrency.name; 
      console.log("Opportunity Currency Name: " + opportunityCurrencyName + " | Currency Id: " + opportunityCurrencyId);
      
      // Compare the Opportunity currency with the Account currency
      if (accountCurrencyId !== opportunityCurrencyId) {
      console.log("Currencies do not match. Updating Opportunity currency to match Account currency.");
      
      // Update the Opportunity currency to match the Account currency
      formContext.getAttribute("transactioncurrencyid").setValue([{
      id: accountCurrencyId, 
      name: result.transactioncurrencyid.currencyname, 
      entityType: "transactioncurrency"
      }]);
      
      // Save the form after the currency is updated
      formContext.data.entity.save();
      } else {
      console.log("Currencies match. No update required.");
      }
      } else {
      console.log("No currency is associated with this opportunity.");
      }
      }
      },
      function(error) {
      console.log("Error retrieving account currency: " + error.message);
      }
      );
      } else {
      console.log("Opportunity is not open. No currency update will be performed.");
      }
      },
      function(error) {
      console.log("Error retrieving opportunity status: " + error.message);
      }
      );
      } else {
      console.log("No account is associated with this opportunity.");
      }
      }
  2. Save and Publish the Web Resource:
    • Click Save and then Publish the web resource.

Step 3 : Add the JavaScript to the Opportunity Form for the Account Field onChange Event

In addition to loading the script when the form is loaded, we’ll also trigger it when the Account field is changed by the user.

1. Go to the Opportunity Form Editor:

  • In the solution editor, select the Opportunity entity, and click on Forms.
  • Open the Main form for editing.

2. Add the JavaScript Web Resource to the Form (if not already added):

  • If you’ve already added the currencySync.js web resource in the previous steps, you don’t need to do this again.
  • If not, click on Form PropertiesForm LibrariesAdd, and select the currencySync.js web resource.

3. Attach the Function to the Form Load Event (if not already done):

  • In the Event Handlers section under Form Properties, add the function as before for the OnLoad event.
  • Make sure to set the correct event handler details:
  • Do the same for On Save, so when the opportunity is saved, the function will check if the currency needs to be updated.

4. Attach the Function to the Account Field onChange Event:

  • In the Form Editor, locate the Account field (which is the parentaccountid field in Dynamics).
  • Double-click on the Account field, or select it and click Change Properties.
  • Go to the Events tab of the field properties.
  • Under Field Events, click Add.
  • In the Library dropdown, select the currencySync.js library (if not already added).
  • In the Function Name field, enter getDetailsFromOpportunity (the same function name as used for the onLoad event).
  • Uncheck the box that says “Pass execution context as the first parameter,” if it’s checked.
  • Click OK to save the event handler for the Account field’s onChange event.

5. Save and Publish the Form:

  • Save the changes made in the form editor.
  • Click Publish to make the changes live in Dynamics 365.

Testing the onChange Event

Now, your JavaScript function will be triggered both when the Opportunity form loads and when the Account field is changed.

Test the Functionality:

  1. Open an Opportunity in Dynamics 365.
  2. Change the Account value, and ensure that the script compares the Opportunity currency with the new Account currency.
  3. If the currencies don’t match, the Opportunity currency should update automatically.

Have any questions on this script, or happy that it worked for you? Leave a comment below!

AccessOrange is a leading Microsoft Partner that specializes in Microsoft 365, Dynamics 365 and Azure to help our customers work smarter.
If you need help with building this solution in your own environment, leave your contact information below, and we will contact you as soon as possible.

"*" indicates required fields

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.
This field is for validation purposes and should be left unchanged.

Dynamics 365 Sales provides businesses with a centralized platform to manage their customer interactions, account information, and sales processes. With Dynamics 365 you can keep track of your customer accounts and contacts by allowing your team to store and access all customer-related data in one place.

In Dynamics 365 Sales it is possible to link contacts to accounts. This feature allows you to associate individual contacts with their respective customer accounts, allowing for a more comprehensive view of customer interactions and relationships.

By linking contacts to accounts, you can easily access information about an individual contact’s role within their company, as well as view a complete history of interactions with the entire organization. This information you can use to personalize interactions with customers, track the progress of opportunities and deals, and make informed decisions about future sales and marketing efforts.

Unfortunately, the process of linking contacts is a manually process, where the user who creates the contact have to manually select to which account it belongs. This manual process is time consuming, and often is forgotten along the way, making your CRM database less effective.

Therefore we have come up with a solution to automatically link your customer contacts to your accounts via Power Automate!

The solution to automatically link your contacts to your accounts with Power Automate

First of all, we assume that all your contacts have an email address, and that your customers all have a unique email domain (which should be reasonable!). We will use this email address to build a relationship between your Account and the related contacts.

First of all, we will create a custom field called “email domain” under our account card. Here is an example:

In this field, we will input the email domain of the customer. This will be used in our Power Automate script to link all the individual contacts to the Account master.

Step 1 – Create custom field for email domain

Go to Advanced Settings

Under Settings, click Customizations

Click Customize the System

Under the customization screen, find the entity Accounts and go to Fields

Here we will add our new email domain field by clicking on New 

Create the field name, and configure the settings as below

Click Save & Close and return to the previous screen

Now we will go to the Forms section and add our custom field to the accounts form

Note that you can also add the field on other forms if you want, for example the Account Quick Create, so when your sales team creates a new account via outlook, they also will be able to enter the domain field there.

Find your email domain field on the right and drag it to the location you want to have it on the form.

Click Save and Close

Click Publish All Customizations

Now you have the email domain field on your account card, where you can enter the email domain of the customer!

After this step we can now move on to the Power Automate Script.

Step #2 – Power Automate Script to Link Contacts to Accounts

Go to Power Automate and create a new flow

Click Build your Own

We will use a scheduled trigger to keep things simple, so every day our new contacts will be linked to their master account.

Go into the flow and start adding the next step

Next we need to filter out all the accounts where the email domain is not empty:

Next is we need to create an Apply to Each loop so we loop through all the records that we found. We can simply start by adding a Compose to our next step, which will automatically create the loop. We can put our email domain field in the compose.

Next, we want to handle multiple entries in the email domain field. We imagine that some accounts may have multiple email domains, hence we will fill them in under the new field as: domain1.com,domain2.com,domain3.com.

In order for our power automate to process them all, we need to first split our field into separate variables and then loop through them. We first split the string into an array by doing a compose with a split command.

After that we will create another loop by creating an Apply to each on the compose output.

Now we have created the loop neccesary for going through all the acounts and all respective email domains.

The next step is to retrieve all the contacts that have the current selected domain in their email address, and are not yet linked to the Account.

We can do that with a Dataverse List Rows command, and a filter.

Now we have all the contacts that are not yet linked, so we can loop through them and link them.

We start with creating an Apply to All by adding a Compose (the easy way to create an apply to all)

Next we do a quick check if the Contact has not been linked to another account already. (As sometimes maybe user may have an email from a domain linked to customer A, but somehow may still be related to another account in your Dynamics, so we need to check if he/she has not been linked already to another account)

If the Parent Customer ID Value is null, it means the contact is not yet linked and we can proceed with linking it to our Account via a Dataverse Relate action.

We add one more Send Email flow to inform ourselves of a succesful link.

And we are done!

Now we can run the flow and we can see that all the contacts with the same email domain have been succesfully linked:

Complete Flow

Here is a screenshot of our entire flow:

Questions? Leave a message below.

We can also help you build this (and other) flows. Contact us via [email protected] if you need assistance with Power Automate or Dynamics 365 Sales.

 

 

 

Dynamics 365 Sales is a customer relationship management (CRM) software solution that is part of the Dynamics 365 suite of business applications. It is designed to help sales teams manage their relationships with customers and prospects and streamline sales processes. With Dynamics 365 Sales, salespeople can access customer data and interactions from a single platform, track sales activities and opportunities, automate tasks, and collaborate with other team members and departments.

Dynamics 365 can be used by Microsoft Power Automate to automate almost anything within Dynamics 365. Dynamics 365 and Power Automate together, make a great combination for further enhancement of your sales process.

In this example we will teach you how to use Power Automate to send a message to your sales staff via Microsoft Teams when a price change has been detected in a Dynamics 365 Pricelist.

Step 1: Create new Power Automate Flow

Go to https://make.powerautomate.com/ and click on “Create”, and select “Automated Flow”

Step 2: Enter Flow name and select Dataverse

Give the flow a name, and search for “dataverse” and select “When a row is added, modified or deleted”

Step 3: Configure Trigger that will start up our Flow

On the next screen we will configure the trigger. We will configure the Change Type to “modified” to ensure that the trigger only runs when a price list has been modified.

Table name: Price List Items (as we want to target Price List Changes in this case)

Scope: Organization (We want this flow to run for the entire dataverse organization, not just our user scope)

Step 4: Get details of product thas has been modified in the price list

First we need to get the record of the Product that had a price change. We will add a new action to our flow and search for “dataverse” and select “get a row by ID”

We will select the table name “Products” and for Row ID we will select “Product (Value)”

Step 5: Get Price List Currency

In our case we have price lists with different currencies, hence we will need to retrieve the actual currency of the pricelist.

We do that again with a Dataverse : Get Row by ID and select Currencies and Row ID: Currency (Value)

Step 6: Create Chat Message

Since the Teams “Post message in a chat or channel” is sometimes buggy when it comes to message layouts, it is recommended to draft your message in a compose, and parse the compose to the next step.

Here is our chat  message including a little layout tweaking such as adding <strong> </strong> to make some letters bold.

We want to show the product code, which in our case is a custom field named “Product ID”.  The amount is the local amount from the price list, for which we add the Curency as well in order to be complete.

Step 7: Post Message in a Chat or Channel

Now we can do the final step, which is to post our chat message in a group chat or in a channel. In our case we have a chat specifically for our sales team, where we want to post the message in.

The actual message is the output of our compose in step 6

When you’re done with above, the entire flow should have the following elements:

Now you can test your flow, and (hopefully) it should work. Here is an example of how it looks on our side:

Great Work! Feel free to reach out if you have any issues or questions regarding above flow.

Dynamics 365 Sales is a cloud-based CRM solution that enables salespeople to build strong relationships with their customers, take actions based on insights, and close deals faster. With Dynamics 365 you can manage your customer relationships, from first contact (lead) to qualifying (opportunity) to deal (Quote/Order).

Dynamics 365 can be used by Microsoft Power Automate to automate almost anything within Dynamics 365. Dynamics 365 and Power Automate together, make a great combination for further enhancement of your sales process.

In this example we will teach you how to use Power Automate to send a message to your sales staff via Microsoft Teams when a new lead has been assigned to them in Dynamics 365.

Step 1: Create new Power Automate Flow

Go to https://make.powerautomate.com/ and click on “Create”, and select “Automated Flow”

Step 2: Enter Flow name and select Dataverse

Give the flow a name, and search for “dataverse” and select “When a row is added, modified or deleted”

Step 3: Configure Trigger that will start up our Flow

On the next screen we will configure the trigger. We will configure the Change Type to “added or modified” to ensure that the trigger only runs when a new lead is added, or when a lead is modified.

Table name: Leads (as we want to target leads in this case)

Scope: Organization (We want this flow to run for the entire dataverse organization, not just our user scope)

Select Columns: We will enter “ownerid” here because we want to make sure that our trigger only runs when the field “ownerid” (which is the lead owner) is added or changed

Step 4: Get Current Lead

First we need to get the record of the lead that had an addition/change to the lead owner. We will add a new action to our flow and search for “dataverse” and select “get a row by ID”

We will select the table name “Leads” and for Row ID we will select “lead ID”

Step 5: Ignore Closed Leads

To make sure we’re not going to process leads that have been closed already, we need to filter out the closed leads with a condition. We can do that by terminating the flow if the “Lead Status” is equal to 0.

 

Step 6: Get Lead Owner

For the leads that are not closed, we continue by getting the lead owner from the relationship between table “leads” and “users”. We can do that by retrieving the Table “Users” and get the row id from the Owner Value from the Leads.

Step 7: Get Lead Owner Email Address

Since we want to send a teams message, we will need to retrieve the primary account UPN for that particular owner. We can do that by creating an action called “Get user profile (V2)”, and search the user based on the primary email address we got from the previous step.

Step 8: Get a Mention token for a user in Teams

Since we want to send a message in a particular channel, and tag the owner in the message, we need to get a “mention token” for this user. We can do this with the task “Get an @mention token for a user” from Teams, and use the user principal name we got from the previous step:

Step 9: Delay task for 1 Minute

In order to make sure that Teams is ready to accept our message with mention token, it is recommended to add a 1 minute delay, to make sure no errors occur:

Step 10: Post a Message in a Chat or Channel

Now we have all the information we need, we can post a message in a Teams Channel. In our case we post it in a group chat, but you can also choose a channel.

For the message, we will include not only the Lead Company Name and Lead Topic, but we also want to include a link to the actual lead in dynamics.

Make sure that you enter the fields using the Code View “</>” option, so your urls will not be truncated or broken. In the Code View option, you can enter HTML code to change the layout of the text. (We use <p> for paragraphs, <br> for lines etc

You can see from above screenshot, we first add the “mention token” and then we also include a link to the URL of the lead in Dynamics.

How to get the Lead URL in Dynamics:

  1. Go to Dynamics 365 – Leads
  2. Click on any Lead
  3. Extract the URL from your browser, and remove the last guid from the url (see orange below)

The URL you should use should looks something like:

https://xxxxxxxxxxxxx.dynamics.com/main.aspx?appid=xxxxxx&pagetype=entityrecord&etn=lead&id=

Now paste that in your Flow and make it a Link using the html <a href=””>  lead </a> code.

When you’re done, your flow should have the following steps:

Now you can test your flow, and (hopefully) it should work. Here is an example of how it looks on our side:

Great Work! Feel free to reach out if you have any issues or questions regarding above flow.