Hello Everyone!
The other day I was playing around with some data on CRM and I was about to deactivate a list of 20 records when I accidentally clicked on the Activate button, rather than the Deactivate one.
What was my surprise when I saw that my records kept the state Active however the status reason of all of them went back to the Default one, “New” in this case, tried to replicate again the issue with Activities and it also happened!
Give a try yourselves, it is an interesting bug 😉
I raised it with Microsoft and hopefully they will fix it for the Leo Release.
Scenario:
Entity: Dummy Entity
State: Active / Inactive
Status Reason: New/ Status 1 /Status 2/ Status 3
If we select a record of the list and we click the Activate button, it will keep the state as active however the status will change to the default one!
Imagine we have an entity called Payment that goes through several statuses, this can be a big problem as we could potentially break all our Dashboards and MI.
Solution:
If this is happening to you and you don’t want to wait for Microsoft to fix it in one of the next releases, the best option is to create a plugin to stop this from happening.
Plugin information:
Entity: All
Message Name: SetStateDynamicEntity
Stage: PreInsideTransaction (20)
PreImage:
- Name: PreImage
- Attributes: statecode,statuscode
Main Logic of the Plugin:
protected void ExecutePreOperationActivateDeactivate(LocalPluginContext localContext) { if (localContext == null) { throw new ArgumentNullException("localContext"); } IPluginExecutionContext context = localContext.PluginExecutionContext; Entity preImageEntity = (context.PreEntityImages != null && context.PreEntityImages.Contains(this.preImageAlias)) ? context.PreEntityImages[this.preImageAlias] : null; #region Main Logic if (localContext.PluginExecutionContext.InputParameters.Contains("EntityMoniker") && localContext.PluginExecutionContext.InputParameters["EntityMoniker"] is EntityReference) { if (!localContext.PluginExecutionContext.InputParameters.Contains("State")) { localContext.Trace("There is no State"); } if (!localContext.PluginExecutionContext.InputParameters.Contains("Status")) { localContext.Trace("There is no Status"); } //The PluginExecutionContext contains 3 parameters : EntityMoniker, State and Status //Retrieve the Parameters from the Input Parameters EntityReference targetEntity = (EntityReference)localContext.PluginExecutionContext.InputParameters["EntityMoniker"]; OptionSetValue stateToBe = (OptionSetValue)localContext.PluginExecutionContext.InputParameters["State"]; OptionSetValue statusToBe = (OptionSetValue)localContext.PluginExecutionContext.InputParameters["Status"]; localContext.Trace(String.Format("stateToBe: {0} ; statusToBe: {1}", stateToBe.Value, statusToBe.Value)); //Retrieve the Target Entity target = localContext.OrganizationService.Retrieve(targetEntity.LogicalName,targetEntity.Id,new Microsoft.Xrm.Sdk.Query.ColumnSet("statuscode","statecode")); //Retrieve Original State OptionSetValue state = ((OptionSetValue)target.Attributes["statecode"]); //Retrieve Original Status OptionSetValue status = ((OptionSetValue)target.Attributes["statuscode"]); localContext.Trace(String.Format("state: {0} ; status: {1}", ((OptionSetValue)target.Attributes["statecode"]).Value,((OptionSetValue)target.Attributes["statuscode"]).Value)); //Check if the record was already active/inactive and if so don't try to activate or set as inactive again if ((state.Value == stateToBe.Value) && (statusToBe.Value == -1 ||statusToBe.Value == status.Value)) { throw new InvalidPluginExecutionException("You cannot activate/deactivate a record that is already active/inactive"); } } else throw new InvalidPluginExecutionException("Sorry, current entity record couldn't be found in the current plugin context as a target"); #endregion }
Registry File, remember it is important to register it for all entities!
<Solution Assembly="ActivateDeactivateSolution.Plugins.dll" Id="" IsolationMode="Sandbox" SourceType="Database"> <PluginTypes> <Plugin Description="Plug-in to PreOperationActivateDeactivate" FriendlyName="PreOperationActivateDeactivate" Name="ActivateDeactivateSolution.Plugins.PreOperationActivateDeactivate" Id="" TypeName="ActivateDeactivateSolution.Plugins.PreOperationActivateDeactivate"> <Steps> <clear /> <Step CustomConfiguration="" Name="PreOperationActivateDeactivate" Description="Pre-Operation of Account SetStateDynamicEntity" Id="" MessageName="SetStateDynamicEntity" Mode="Synchronous" PrimaryEntityName="" Rank="1" SecureConfiguration="" Stage="PreInsideTransaction" SupportedDeployment="ServerOnly"> <Images> <Image Attributes="statecode,statuscode" EntityAlias="PreImage" Id="" MessagePropertyName="entityMoniker" ImageType="PreImage" /> </Images> </Step> </Steps> </Plugin> </PluginTypes> </Solution>
Hope it helps!
Thanks,
Mario