Dynamics 365 Editable Grid Events & Methods

 

The much-awaited capability of editing a CRM grid inline is one of the new features in Dynamics 365. Using this functionality improves the productivity of the CRM user by significantly reducing the number of mouse clicks.

 

Editable grid is available as a UI control which can be added to an entity through entity customization. Addition of the editable grid to the desired entity will make all the entity views for that entity inline editable allowing the users to make in-place updates to the values of the grid view columns. The editable grid control also enables a very useful feature to group the records in the view by selected view columns. Using form customizations, this control can also be added to the subgrids on the form enabling them for inline edits.

To interact with the editable grid developers can write scripts which can be executed on the following grid events.

  • OnChange
  • OnRecordSelect
  • OnSave

The following table details out several editable grid methods to access the grid control elements and their values programmatically.

Method

Description Implementation

Grid Methods

getGrid() –  Returns the grid object

–  Contains information about all the grid elements

CRM Editable Grid 1
getRows() –  Returns an enumerable collection of data row of the grid

–  Contains information about the row elements of the grid

–  Returns all the rows displayed on the UI

CRM Editable Grid 2
getSelectedRows() –  Returns an enumerable collection of selected data rows of the grid

–  Returns data related to one or more rows selected on the UI

CRM Editable Grid 3
getTotalRecordCount() –  Returns the count of the number of rows in an entity view  

CRM Editable Grid 4

Grid Row Methods

getData(),

getKey(), getData().getEntity(), getData().getEntity().getEntityName(), getData().getEntity().attributes

–  Returns an object of the row data specific to the record displayed/selected in the grid

–  Contains entity information, attributes information and related entity information

–  Attributes returned are limited to the columns presented in the editable grid

CRM Editable Grid 5

 

Grid Cell Methods

setNotification(),

clearNotification(),

getName(),

getLabel()

–  Each grid cell is associated with a UI control like text, lookup, picklist

–  Information related to these control is available in the attribute collection

–  These controls can be accessed in a similar way as on the entity form

 

CRM Editable Grid 6

 

Hope you find it useful, stay tuned for more updates.

Thank you,
Swaroop Deshmukh
Lead Dynamics CRM Consultant @ Adisys

Advertisement

Dynamics CRM Scripting for Business Process Flows

Dynamics CRM 365/ Dynamics CRM 2015/ CRM 2016 lets the developers interact with the business process flows by writing client-side scripts. Business Process flow actions can be performed programmatically by making use of the methods under Xrm.Page.data.process and Xrm.Page.ui.process namespaces.

To interact with the business process flow, in addition to the entity form events, two new events onStageChange() and onStageSelected() event are provided by the client API.

Below is the list of methods for tapping into the  Business Process Flow capability.

Method Description Implementation
Process Methods
getEnabledProcesses –  Executes asynchronously

–  Retrieves the information about all the business process flows enabled for the entity

–  Returns a dictionary object where Id is the key and Name is the value

//GetEnabledProcesses

Xrm.Page.data.process.getEnabledProcesses(function (processes) {

for (var processId in processes) {

alert(“Id:” + processId + “, Name:” + process[processId]);

}

});

setActiveProcess –  Executes asynchronously

–  Sets the business process flow for the entity passed as a parameter

–  Returns the status of the operation (success or invalid)

// Set Active Process

Xrm.Page.data.process.setActiveProcess(processId, function (status) {

alert(status);

});

getActiveProcess –  Retrieves the information about the active business process flow for the entity

–   Returns an object containing the data for the active process

var id, processName, stageCount;

var activeProcess = Xrm.Page.data.process.getActiveProcess();

if (activeProcess != null) {

// Get Process Id

id = activeProcess.getId();

// Get Process Name

processName = activeProcess.getName();

// Get Process stage count

stageCount = activeProcess.getStages().getLength();

}

setDisplayState –  Displays the business process flow as expanded or collapsed

–  Display state is passed as a string parameter to the function

if (Xrm.Page.ui.process.getDisplayState() == “collapsed”) {

// Set the display as expanded

Xrm.Page.ui.process.setDisplayState(“expanded”);

}

else {

// Set the display as collapsed

Xrm.Page.ui.process.setDisplayState(“collapsed”);

}

setVisible –  Shows or hides the business process flow

–  Boolean parameter to show (true) or hide (false) the process

if (!Xrm.Page.ui.process.getVisible()) {

// Show the business process flow

Xrm.Page.ui.process.setVisible(true);

}

else {

// Hide the business process flow

Xrm.Page.ui.process.setVisible(false);

}

Stage Methods
getStages –  Retrieves the information about a specific stage in the process identified by the index value

–  Returns an object containing the data related to a particular stage in a process

var stageObj,stageId, stageName, stageEntityName, stageCategory, stageStatus;

var activeProcess = Xrm.Page.data.process.getActiveProcess();

if (activeProcess != null) {

// Get the First stage object of the process

stageObj = activeProcess.getStages().get(0);

// Get Stage Id

stageId = stageObj.getId();

// Get Stage Name

stageName = stageObj.getName();

// Get Stage Entity name

stageEntityName = stageObj.getEntityName();

// Get Stage Category

stageCategory = stageObj.getCategory().getValue(); // – integer value of the stage

// Get Stage Status

stageStatus = stageObj.getStatus(); // – active/inactive

}

getActiveStage –  Returns an object representing the current active stage of the process var activeStage;

// Get Active Stage object

activeStage = Xrm.Page.data.process.getActiveStage();

setActiveStage –  Executes asynchronously

–  Sets a completed stage for the current entity as the active stage

// Sets the Stage identified by the id as the active stage

Xrm.Page.data.process.setActiveStage(stageId, function (data) {

alert(data);

});

getActivePath –  Retrieves a collection of stages currently in the active path.

–  Contains information for completed stages, current active stage as well as predicted future stages based on the data on the current record and branching rules for the process

 

// Get Active Path

var activePath = Xrm.Page.data.process.getActivePath();

if (activePath != null) {

activePath.forEach(function (stage, n) {

alert(” Stage Index: ” + n + “\n Entity: ” + stage.getEntityName() + “\n StageId: ” + stage.getId() + “\n Status: ” + stage.getStages());

 

})

 

}

Step Methods
getSteps –  Retrieves the information of all the steps in a particular stage of the process var stepCollection, stepCount, stepObj,stepName,stepAttributeName,isStepReq,stepType;

var activeStage = Xrm.Page.data.process.getActiveStage();

if (activeStage) {

 

// Get Step count

stepCount = activeStage.getSteps().getLength();

// Get the Steps of a stage

stepCollection = activeStage.getSteps();

// Get the First Step object of the stage

stepObj = activeStage.getSteps().get(0);

// Get the Step Name

stepName = stepObj.getName();

// Get the Step Attribute name

stepAttributeName = stepObj.getAttribute();

// Check whether the Step is required

isStepReq = stepObj.isRequired();

// Get the Step type

stepType = stepObj.getStepType();

}

Navigation Methods
moveNext –  Progresses the process to the next stage

–  Works only when the selected stage and the active stage are the same

–  Triggers the onStageChange event

–  Returns the status in a callback function indicating the operation status (success, crossEntity, end, invalid)

// Move Next

Xrm.Page.data.process.moveNext(function (status) {

if(status == “success”)

alert(“Moved to next stage”);

});

movePrevious –  Moves the process to the previous stage

–  Works only when the selected stage and the active stage are the same

–  Triggers the onStageChange event

–  Returns the status of the operation

// Move Previous

Xrm.Page.data.process.movePrevious(function (status) {

if(status == “success”)

alert(“Moved to previous stage”);

});

 

Event Handler Methods
addOnStageChange –  Adds a function as an event handler for the onStageChange event

–  Event handler function executes when Next or Previous button is clicked on the process UI

// Add onStageChange event handler

Xrm.Page.data.process.addOnStageChange(stageChanged);

 

function stageChanged(execContext)

{

// Get direction

var direction = execContext.getEventArgs().getDirection();

// Get the current stage object

var currentStage = execContext.getEventArgs().getStage();

}

removeOnStageChange –  Removes a function as an event handler for the onStageChange event // Remove onStageChange event handler

Xrm.Page.data.process.removeOnStageChange(stageChanged);

addOnStageSelected –  Adds a function as an event handler for the onStageSelected event

–  Event handler function executes whenever a stage of an business process flow is selected

// Add onStageSelected event handler

Xrm.Page.data.process.addOnStageSelected(stageSelected);

 

function stageSelected(execContext)

{

// Gets the current stage

var currentStage = execContext.getEventArgs().getStage();

}

removeOnStageSelected –  Removes a function as an event handler for the onStageSelected event // Remove onStageSelected event handler

Xrm.Page.data.process.removeOnStageChange(stageSelected);

Hope you will find it useful!

Cheers
Swaroop
Adisys Engineering Team

Dynamics CRM 2016 Solution Patching

Dynamics CRM 2016 Enhancement- Solution Patching

As we already know concept of solution was introduced in Dynamics CRM 2011, in Dynamics CRM 2015 there was cosmetic changes made in solution management. In this release they added significant improvements to manage solutions in better and deeper way.

Earlier versions if you wanted to export any field or any new specific customization of an entity you had to export entire entity itself.

If we export the solution, the entity and all customizations and related components like views, relationships, Ribbon, UI changes and any other components that are part of the entity are exported in that solution. Importing entity means deploying all customization to target environment. Sometime we want to avoid this but it was not possible in earlier versions.

In Dynamics CRM 2015 there was no enhancement in Solution framework but in Dynamics CRM 2016 Solutions and customizations are more manageable.

In Dynamics CRM 2016 we can include specific components in solution instead of including all entity assets as shown in picture below:

Dynamics CRM 2016 Solution Patch - Account

Dynamics CRM 2016 Solution Patch – Account

 

I will give a real time example that we face challenges every time. Suppose we deployed some solution to production.  Sometimes, due to last minute change requests or emergency fixes need to push to UAT or Production environment right after deployment. We are already working on some enhancement in DEV and in between we did Emergency fix to CRM Form or fields and created new fields. In this scenario we just want to deploy emergency fixes that we did for form or created new field or modified anything in field or any change to a particular form for particular entity that is already deployed to production.  We don’t want to deploy other enhancements that are still under development. We just want to deploy the  Hotfix (patch).

In this scenario Dynamics CRM 2016 solution patching made it easier!

To address this, you can create and publish solution patches on top of existing solution that contains subcomponents of entities.

I will explain how solution patching works here:

I have created a MyTestPathEntity Entity and added to solution MyEntity.

Now I will create a patch for solution. You can select a solution and click Clone a Patch button. See in below screen shot You can change the display name and build numbers of the solution. You can’t change the Major and Minor versions.

Dynamics CRM 2016 Solution Clone to Patch

Dynamics CRM 2016 Solution Clone to Patch

It will create a solution Patch like below. It will be a blank solution without any component.

Dynamics CRM 2016 Solution

Dynamics CRM 2016 Solution

 When you will try to edit the Parent solution it will show below message.

Dynamics CRM 2016 Solution - Custom Entity

Dynamics CRM 2016 Solution – Custom Entity

In Patch solution I have just added my custom field.
Field name is new_testoptionset.
Field is of type OptionSet.
I have added one more OptionSet value to existing OptionSet.
Now as Parent solution is already available in target environment you can just import Patch solution.

Solution should be deployed to target environment in below order.

  • Parent solution
  • Patch Solution

You can’t deploy Patch solution before Parent solution. You might be thinking how CRM is checking the dependency.

Patches are stored in the CRM database as Solution table. ParentSolutionId attribute indicates that the solution is a patch.  Patch solution will be having reference to Parent solution.

If you have more than 1 patch. You should deploy in the order you have created.

If you want to merge parent solution and all patches you can clone solution.  It will create an incremented version of solution and merge patches into the new solution. When you will click Clone solution button you can see below screen. You can modify Major minor version but you can’t modify Build and revision number.

Now after clone I can see only 1 solution with incremented version.

Dynamics CRM 2016 Solution - Version

Dynamics CRM 2016 Solution – Version

Few important things to remember as per the MSDN.

  • Patches can only be created from a parent solution.
  • The patch parent can’t be a patch. It won’t allow you to create a Patch from Patch.
  • Patches can only have one parent solution.
  • A patch creates a dependency (at the solution level) on its parent solution.
  • You can only install a patch if the parent solution is present.
  • A patch version must have the same major and minor number, but a higher build and release number, than the parent solution version number. The display name can be different.
  • If a solution has patches, subsequent patches must have a numerically higher version number than any existing patch for that solution.
  • Patches support the same operations as solutions, such as additive update, but not removal. You cannot remove components from a solution using a patch.
  • Patches exported as managed must be imported on top of a managed parent solution. The rule is that patch protection (managed or unmanaged) must match its parent.
  • Don’t use unmanaged patches for production purposes.
  • Patches are only supported in CRM organizations of version 8.0 or later.

We would love to hear your feedback.
Happy CRMing!!
Kalim
Adisys Engineering Team

 

Introducing Transactions with Dynamics CRM 2015

 

We always wanted a transactions capabilities when you are performing business logic in enterprise applications, given the complexity of the application, integration or business rules. Transactions gives full capability to manage application behavior.

In order to implement transactions through windows or web based applications we used to write our own logic to roll back the operations in case of any business logic failure or change in data status.

We can take the example of my project where I wanted to rollback all operations in case of payment failure while buying order through online portal. In case of payment failure, I wrote my own logic to rollback records.

In Dynamics CRM 2015 update 1, as transactions been introduced, I was able to use ExecuteTransactionRequest, this is  helpful to maintain integrity during the context of transactions.

We can execute multiple operations in single database transaction so that either all operations will be executed successfully or none (revert back).

You need to add the reference to Microsoft.Xrm.Sdk dll.. We can provide collection of Organization request as given in below example.  I have added 3 requests to the collection. ExecuteTransactionRequest takes request collections as a parameter

public static void PerformTransactionOperation(OrganizationService service)
{
var request = new ExecuteTransactionRequest()
{
Requests = new OrganizationRequestCollection()
};

var account = new Entity(“account”);
account[“name”] = “Account Test”;
var createRequest = new CreateRequest() { Target = account };
request.Requests.Add(createRequest);

RetrieveRequest retReq = new RetrieveRequest() { Target = new EntityReference(“account”, new Guid(“B6F79317-5E8E-E511-80E7-3863BB2E1390”)) };

retReq.ColumnSet = new ColumnSet(“name”);
request.Requests.Add(retReq);
Entity accToUpdate = new Entity(“account”);

accToUpdate.Id = new Guid(“B6F79317-5E8E-E511-80E7-3863BB2E1390”);
var updateRequest = new UpdateRequest() { Target = accToUpdate };
request.Requests.Add(updateRequest);
try
{
var respTrans = (ExecuteTransactionResponse)service.Execute(request);
foreach (var response in respTrans.Responses)
{
switch (response.ResponseName.ToUpper())
{
case “CREATE”:
var createResponse = (CreateResponse)response;
Console.WriteLine(“Account created: {0}”, createResponse.id);
break;

case “UPDATE”:
var updateResponse = (UpdateResponse)response;
break;

case “DELETE”:
var deleteResponse = (DeleteResponse)response;
break;

case “SETSTATE”:

var setstateResponse = (SetStateResponse)response;

break;

case “RETRIEVE”:
var retResponse = (RetrieveResponse)response;
break;
}}}
catch (FaultException<OrganizationServiceFault> ex)
{
ExecuteTransactionFault fault = (ExecuteTransactionFault)ex.Detail;
}}

It will be executed in the same order as it was added to collection.

In our case we got 3 responses for each request. In my code, I am checking the Response name and accordingly performing each operation.

If you want to know the exact request that was failed, you can check the FaultedRequestIndex as given below. It will tell you the index number of the request that was failed.

Few important points to Note:

  • An ExecuteMultipleRequest may have multiple ExecuteTransactionRequest instances.
  • An ExecuteTransactionRequest instance may not contain a ExecuteMultipleRequest or ExecuteTransactionRequest.
  • It has same limit as ExecuteMultipleRequest. Maximum batch size could be 1000. You can have maximum 1000 Requests in a batch.
  • CRM online can have maximum 2 Concurrent batch request.
  • If you have more than 1000 Requests you have to split the requests in batches.

Hope this Post is helpful. I would love to hear your suggestions.

Happy CRMing!!!!!!!!
Thank you,
Kalim Ansar
Adisys Corporation

Set Custom Help URLs in Dynamics CRM Online 2015

Set Custom Help URL CRM Online 2015
Custom Help URL is another exciting feature in Dynamics CRM 2015. Administer can simply enable and configure the URL at both Global Level and Entity Level.

There are 3 kind of Help URL:

  • Build-in CRM Help (Default)
  • Global Level Custom Help
  • Entity Level Custom Help (Support both OOB entity and Custom Entity)

1)    Build-in CRM Help:

Below is the built-in CRM Online Help hosted on Microsoft website. User will be navigated to this online knowledge base center by default after clicking on Help link.

Dynamics CRM Help #1

Dynamics CRM Help #1

Dynamics CRM Help #1

 

 

 

 

 

 

2)     Custom URL at Global Level

System administrator can configure Global custom Help URL. Go to Settings -> Administration -> System Settings -> General:

Dynamics CRM Help #2

Dynamics CRM Help #2

 

 

Global Custom Help URL link in CRM:

Dynamics CRM Help #3

Dynamics CRM Help #3

 

3)     Entity Level Custom Help URL

To enable and configure the custom help URL on a specific entity form, administrator can go to Entity Customization:

Dynamics CRM Help #4

Dynamics CRM Help #4

 

Help Link on Entity form:

Dynamics CRM Help #5

Dynamics CRM Help #5

Hopefully you will find it useful!
Thank you,
Zhe Chen
Adisys Corporation

Set Hierarchy Security in Dynamics CRM Online

We have a requirement to allow the manager to view and update the records owned by the direct report.

In Dynamics CRM 2015 introduced hierarchy security model in CRM 2015 Update 1 which make it super easy to implement this kind security requirement.

Hierarchy security is an extension to the existing security models that use business units, security roles, sharing, and teams. There are two security options in Hierarchy Security Model:

  • Management Chain, based on the direct reporting structure and the hierarchy depth
  • Position Hierarchy, based on the defined job positions and the hierarchy depth
Dynamics CRM 2015 Hieararchy Security

Dynamics CRM 2015 Hieararchy Security

 

A user can be assigned to one position and hence get a Read, Write, Update, Append, AppendTo access to the lower positions’ data in the direct ancestor path. The non-direct higher positions, have Read-only access to the lower positions’. Following is a sample of the Position Hierarchy structure defined in CRM.

In this organization, CEO has full access to the data owned by HR Managers, Sales Managers and Service Managers. Sales managers has the full access to the data owned by Sales. Once you have position hierarchy defined in system then administrator can easily assign the user for the position to get the access accordingly.

Dynamics CRM 2015 Hierarchy Security #2

Dynamics CRM 2015 Hierarchy Security #2

Hopefully you find it useful!
Thank you,
Zhe Chen
Adisys Corporation

Time-Zone Independent Date Field in Dynamics CRM Online 2015

Time-Zone Independent Date Field in CRM Online 2015 Update

 Prior to CRM Online 2015 update 1, CRM saves date in UTC format in Database and show the local date time to user based on the login user’s time zone configuration. It works perfect if you have users around the world. However it might cause some confusions for below scenarios:

  • The exact date not depend on the time zone. Ex: birthday, Anniversary
  • The exact date time not depend on time zone. Ex: Hotel Check in/out Date and time
  • Data migration
  • System/Data Integration

With the latest CRM Online 2015 update release, Microsoft introduces the DateTimeBehavior property to define whether to store date and time values with or without time zone information. Followings are the definition for these three Behavior:

 

CRM Online Time Settings

CRM Online Time Settings

 

Member name and value Description
UserLocal
  • Stores the date and time value as UTC value in the system.
  • The retrieve operation returns the UTC value.
  • The update operation converts the UTC value to the current user’s time zone value, and then stores the updated value as is or as the equivalent UTC value depending on the kind (DateTimeKind) of the value specified for update. If the specified value is of UTC kind, it’s stored as is. Otherwise, the UTC-equivalent value is stored.
  • Retrieving the formatted value converts from UTC to the user’s current time zone based on the time zone and locale setting of the user.
  • For the OData endpoint, the attribute is exposed as DateTimeOffset.
  • This behavior is used for system attributes like CreatedOn and ModifiedOn, and cannot be changed. You should use this behavior for custom attributes where you want to store date and time values with the time zone information.
DateOnly
  • Stores the actual date value with the time value as 12:00 AM (00:00:00) in the system.
  • For the retrieve and update operations, no time zone conversion is performed, and the time value is always 12 AM (00:00:00).
  • Retrieving the formatted value displays the date value without any time zone conversion.
  • For the OData endpoint, the attribute is exposed as DateTimeOffset.
  • This behavior should be used for custom attributes that store birthdays and anniversaries, where the time information is not required.
TimeZoneIndependent
  • Stores the actual date and time values in the system regardless of the user time zone.
  • For the retrieve and update operations, no time zone conversion is performed, and actual date and time values are returned and updated respectively in the system regardless of the user time zone.
  • Retrieving the formatted value displays the date and time value (without any time zone conversion) based on the format as specified by the current user’s time zone and locale setting.
  • For the OData endpoint, the attribute is exposed as DateTimeOffset.
  • This behavior should be used for attributes that store information such as check in and check out time for hotels.

Hopefully you find it useful!
Thank you,
Zhe Chen

Optimistic concurrency in CRM Online 2015 Update 1

Another enterprise capability has been added to the Dynamics CRM 2015 Online Update 1. Kudo’s the Dynamics CRM PG team.  This is going to ease the Optimistic concurrency enablement in the product layer.

Prior to CRM online 2015 update 1, There were no concurrency lock checks out of the box and CRM always saves the value on the field level. The latest transaction will win (Overwrite). Developers might build some customization code to ensure the data integrity. However it requires lot of customization effort.

Provided in the latest SDK release is the ability to detect whether an entity record has changed on the server in the time between when your application retrieved the record and when it tries to update or delete that record.

The ConcurrencyBehavior Property specifies the type of optimistic concurrency behavior that should be performed by the Web service when processing this request:

Member name Description
AlwaysOverwrite Specifies the behavior where an update or delete operation is applied without regard to the version of the record in the database. Value = 2.If optimistic concurrency is not enabled for the target entity, the AlwaysOverwrite behavior is applied.
Default Specifies to use the default behavior. Value = 0. The default value is also used if no value is set in the ConcurrencyBehavior property of the request. The meaning of “default” is interpreted differently based on the calling context.
IfRowVersionMatches Specifies the behavior where an update or delete operation is only applied if the entity record in the database has the same row version as the entity or entity reference in the request. Value = 1.If no row version value is provided on the entity or entity references in the request, the request fails immediately.

The following sample code from SDK shows how to use optimistic concurrency for update and delete operations. The complete sample can be downloaded from MSDN: https://code.msdn.microsoft.com/Use-optimistic-concurrency-e0b0440d.

using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri, serverConfig.HomeRealmUri,serverConfig.Credentials, serverConfig.DeviceCredentials))
{
CreateRequiredRecords();
// Retrieve an account.
var account = _serviceProxy.Retrieve(“account”, _accountId, new ColumnSet(“name”,”creditlimit”));
Console.WriteLine(“\tThe row version of the created account is {0}”, account.RowVersion);

if (account != null)
{
// Create an in-memory account object from the retrieved account.
Entity updatedAccount = new Entity()
{
LogicalName = account.LogicalName,
Id = account.Id,
RowVersion = account.RowVersion
};

// Update just the credit limit.
updatedAccount[“creditlimit”] = new Money(1000000);
// Set the request’s concurrency behavour to check for a row version match
UpdateRequest accountUpdate = new UpdateRequest()
{
Target = updatedAccount,
ConcurrencyBehavior = ConcurrencyBehavior.IfRowVersionMatches
};
// Do the update.
UpdateResponse accountUpdateResponse = (UpdateResponse) _serviceProxy.Execute(accountUpdate);
Console.WriteLine(“Account ‘{0}’ updated with a credit limit of {1}.”, account[“name”],((Money)updatedAccount[“creditlimit”]).Value);
account = _serviceProxy.Retrieve(“account”, updatedAccount.Id, new ColumnSet());
Console.WriteLine(“\tThe row version of the updated account is {0}”, account.RowVersion);
_accountRowVersion = account.RowVersion;
}
DeleteRequiredRecords(promptforDelete);
}

Hopefully you find it useful!
Thank you,
Zhe Chen