Dataverse: Create an API to update Base Currency

This time, I’ve got a request from Trung Dũng Nguyễn where he wants to update the base currency based on the updated Currency inputted into the Transaction Currency table. When I check on the system behavior, the Currency (Base) information will be updated as long as we update at least one “Currency” attribute. Please note that because we need to update the Currency attribute, it might trigger the plugin step you set on that entity.

Sample Currency

Without further ado, here is the code that I prepared for the Custom API:

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using Niam.XRM.Framework;
using Niam.XRM.Framework.Interfaces.Plugin;
using Niam.XRM.Framework.Plugin;
using System;
using System.Linq;

namespace Insurgo.Custom.Api.Business
{
    public class UpdateCurrencyBase : OperationBase
    {

        public const string LogicalNameParameter = "LogicalName";
        public const string EntityIdParameter = "EntityId";

        public UpdateCurrencyBase(ITransactionContext<Entity> context) : base(context)
        {
        }

        protected override void HandleExecute()
        {
            var logicalName = Context.PluginExecutionContext.InputParameters[LogicalNameParameter].ToString();
            if (string.IsNullOrEmpty(logicalName)) throw new ArgumentNullException(nameof(LogicalNameParameter));

            var entityId = (Guid)Context.PluginExecutionContext.InputParameters[EntityIdParameter];

            var entity = GetEntityMetadata(logicalName);
            var moneyAttributes = entity.EntityMetadata.Attributes
                .Where(e => e.AttributeType == Microsoft.Xrm.Sdk.Metadata.AttributeTypeCode.Money
                    && e.IsValidForUpdate.GetValueOrDefault() && e.IsValidForRead.GetValueOrDefault())
                .Select(e => e.LogicalName)
                .ToArray();
            if (!moneyAttributes.Any()) return;

            var currentEntity = Service.Retrieve(logicalName, entityId, new ColumnSet(moneyAttributes));
            var existMoney = currentEntity.Attributes.FirstOrDefault(e => moneyAttributes.Contains(e.Key) && e.Value != null);
            if (existMoney.Key == null) return;

            var updateEntity = new Entity(logicalName, currentEntity.Id)
                .Set(existMoney.Key, existMoney.Value);
            Service.Update(updateEntity);
        }

        private RetrieveEntityResponse GetEntityMetadata(string logicalName)
        {
            var req = new RetrieveEntityRequest
            {
                LogicalName = logicalName,
                EntityFilters = Microsoft.Xrm.Sdk.Metadata.EntityFilters.Attributes
            };

            var result = (RetrieveEntityResponse)Service.Execute(req);

            return result;
        }
    }
}

From the above code, first, we need to have 2 parameters: The Entity Logical Name and also the Entity ID, which will be updated later.

Next, we will retrieve the information about the Entity (using RetrieveEntityRequest with EntityFilters set to “Attributes”). As we just need the Money attributes, then we will filter with that condition and apply the filter for the attributes that can be “Updated” and “Read” (lines 29 – 34).

After we get the information, we need to retrieve the target Entity and select the Money attributes. Once we get the target Entity, we need to scan which Money attribute exists in the target entity and update it (lines 37 – 43).

Once the plugin is ready, the next is to register the plugin, and below is the Custom API that I created for it (whenever I created Custom API, I always use Custom API Manager by David Rivard):

Custom API Definition

The Custom API Definition

Next, to triggering this custom API, I created the below JS:

var tmy_ribbon = tmy_ribbon || {};

(function () {
    this.executeUpdateCurrencyBase = function (formContext) {
        var recordId = formContext.data.entity.getId();
        var logicalName = formContext.data.entity.getEntityName();

        var execute_tmy_updatecurrencybase_Request = {
            // Parameters
            LogicalName: logicalName, // Edm.String
            EntityId: { guid: recordId }, // Edm.Guid

            getMetadata: function () {
                return {
                    boundParameter: null,
                    parameterTypes: {
                        LogicalName: { typeName: "Edm.String", structuralProperty: 1 },
                        EntityId: { typeName: "Edm.Guid", structuralProperty: 1 }
                    },
                    operationType: 0, operationName: "tmy_updatecurrencybase"
                };
            }
        };

        Xrm.WebApi.execute(execute_tmy_updatecurrencybase_Request).then(
            function () {
                var alertStrings = { confirmButtonLabel: "Yes", text: "Base currency has been updated!", title: "Base Currency Alert" };
                var alertOptions = { height: 120, width: 260 };
                Xrm.Navigation.openAlertDialog(alertStrings, alertOptions).then(() => formContext.data.refresh(true));
            }
        ).catch(function (error) {
            console.log(error.message);
        });
    }
}).apply(tmy_ribbon);

If you ask me what is the easiest way to know how to execute it in JS (of course I’ll choose the Xrm.WebApi), I always go to Dataverse Rest Builder by Guido Preite. You only need to select which API you want to call > put sample value parameters:

Dataverse REST Builder

Dataverse REST Builder

Then, go to Xrm.WebApi tab and viola, you got the main logic already:

Generated Xrm.WebApi code

Generated Xrm.WebApi code

Once you have done the above, you just need to deploy the JS file into your environment!

The last part is to create the Ribbon button. Go to your App > Entity that will use this function > Edit Command Bar > select the Main Form. There, you can create a new Command button > Set the label > On the Action select “Run JavaScript” > select the library that you want to call > set the function to invoke (which is tmy_ribbon.executeUpdateCurrencyBase) > Set the parameter to send as “Primary Control“:

Ribbon button definition

Ribbon button definition

Once everything is done, don’t forget to Publish All Customizations, and here is the demo:

Demo update Base Currency!

Happy CRM-ing!

Author: temmyraharjo

Microsoft Dynamics 365 Technical Consultant, KL Power Platform User Community Leader, Student Forever, Test Driven Development, and Human Code enthusiast.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.