Retrieve Plugin not getting triggered - dynamics-crm

We are on Dynamics CRM 2016 On-Premise. Using a plugin I'm trying to automatically update a field when a user open the CRM Account form, in this example to value "5". Here's my code:
var targetEntity = (Entity)context.OutputParameters["BusinessEntity"];
if (targetEntity == null)
throw new InvalidPluginExecutionException(OperationStatus.Failed, "Target Entity cannot be null");
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var service = serviceFactory.CreateOrganizationService(context.UserId);
if (targetEntity.Attributes.Contains("MyField"))
fedTaxId = targetEntity.Attributes["MyField"].ToString();
targetEntity.Attributes.Add("MyField"d, "5");
targetEntity["MyField"] = "5";
service.Update(targetEntity);
I list this in message type 10 (Before Main Operation Outside Transaction).
In Plugin Registration I list this as Post Operation stage and Synchronous.
However when I open the Account form, the page blinks once but the value did not get automatically populated. There is no javascript that would've manipulated this form or value either.
Any suggestion? Thanks.

Two options:
Add a script on the form setting the field value on load. Keep in mind this script should only do its thing if the form type = 2.
(Not recommended) Register a plugin on the synchronous post retrieve message for the entity. Make sure this step sets the field value on the entity object in the OutputParameters collection. Now, keep in mind your form will not be aware of the fact that this field has been modified, so it will not be flagged dirty and it will not automatically be submitted when record changes are being saved. So, in this scenario you would still need to add some JavaScript OR you would need an extra plugin registered on the pre update message of the entity setting the field as desired.

Related

Change record owner in Dynamics CRM plugin

I am writing a Post PLugin changing the owner. When the owner has a substitution manager, the owner is changed to the substitution manager. I tried a service.Update and an AssignRequest, but these throw an exception.
When I post the request my entity cannot update (and then throws "The request channel time out while waiting for reply after 10:00:00"). But like I see there is no recursion, because when I logged it I have only one repetition of log and it has stopped before or on line with update.
var assignedIncident = new AssignRequest
{
Assignee = substManagerRef, //get it throw another method, alreay checked in test it`s correct
Target = new EntityReference ("incident", incedentId)
};
service.Execute(assignedIncident);
I tried to write target in another way
Target = postEntityImage.ToEntityReference()
I tried to write simple update but the problem is the same.
Entity incident = new Entity("incident" , incidentId);
incident["ownerid"] = substManagerRef:
service.Update(incident);
Can somebody help me with that? Or maybe show the way to solve it)
The plugin is triggering itself and gets in a loop. The system only allows a maximum of 8 calls deep within plugins and that is the reason it throws an error and rolls back the transaction.
To solve this issue redesign your plugin in the following way:
Register your plugin on the Update message of your entity in the PreValidation stage.
In the plugin pick up the Target property from the InputParameters collection.
This is an Entity type. Modify or set the ownerid attribute on this Entity object.
That is all. You do not need to do an update, your modification is now passed into the plugin pipeline.
Note: for EntityReference attributes this technique only works when your plugin is registered in the PreValidation stage. For other regular attributes it also works in the PreOperation stage.

Dynamics CRM Getting Account Details

I'm having a problem with the following thing.
In Dynamics CRM I have a Custom Button that created a new Order, the button works great, however, I wanted to make it work as the OOB one and prefilled some of the Account information such as Account Name and Price List (form example).
example
In Ribbon Workbench I've added the following parameter for my button
ribbon settins
The next thing that I've done was to create a new Jscript web resource and add the following code.
references: https://learn.microsoft.com/en-us/dynamics365/customerengagement/on-premises/developer/customize-dev/pass-dynamics-365-data-page-parameter-ribbon-actions
Web resource name: new_getorder
Code: function XrmCore.Commands.Open.openNewRecord(primaryControl) {
var formContext = primaryControl;
}
I've then added the web resource on the Order form where is supposed to trigger when clicking on the custom button from the account form, but I'm getting a script error (which is not a surprise for me)
form properies
I've also enabled Pass execution context as first parameter
Web resource method does not exist: XrmCore.Commands.Open.openNewRecord
new order button from account ribbon
Error when loading the Order form: Web resource method does not exist: XrmCore.Commands.Open.openNewRecord
Instead of custom code, why don't you try Map Entity Field feature?
You can map attributes between entities that have an entity
relationship. This lets you set default values for a record that is
created in the context of another record.
In your scenario, after mapping Account and Price list fields between Account and Order tables, when you will go to the Related > Orders section and try to create an Order from there, those two fields should be pre-filled on the new Order form.
And I think this feature would work also when you have a Orders sub grid on account form and try to create Order from new button on the sub grid.
You may go through the documentation to understand this concept and to check steps to create mapping.
Anyway, I've managed to find my solution by using this script in a custom web resource
enter code here
var entityFormOptions = {};
entityFormOptions["entityName"] = "salesorder";
entityFormOptions["createFromEntity"] = currentRecordRef;;
// Open the form.
Xrm.Navigation.openForm(entityFormOptions).then(
function (success) {
console.log(success);
},
function (error) {
console.log(error);
});

Adding DynamicPropertyInstance doesn't mark the SalesOrderDetail as valid

I have the following code:
var propertyInstance = new DynamicPropertyInstance()
{
DynamicPropertyId = new EntityReference(DynamicProperty.EntityLogicalName, Guid.Parse("0ceedfcc-68b2-e711-8168-e0071b658ea1")),
ValueString = jobId.ToString(),
RegardingObjectId = line.ToEntityReference(),
};
crmContext.AddObject(dynamicPropertyInstance);
crmContext.SaveChanges();
It is successfully adding a DynamicPropertyInstance to a SalesOrderLine, but when viewing the Order in the CRM UI it does not pass the validation (as it is a required property). I've not managed to find a way to make this property valid. Editing the property that I've added in the UI (resetting the value) also fails to mark the instance as valid. Adding exactly the same property through the UI does mark it as valid.
The Id of the DynamicProperty is correct, as verified by loading the 2 instance records through the SDK and comparing the properties. Rather strangely, when I load the 2 records through the SDK the one I've created in code has a validationstatus of true (even though it's not) and the one that I've created in the UI has a validationstatus of false and ValueString returns null (which is wrong). All of the other properties either match or have relevant values (such as dates, object Ids etc)
I'm probably missing a method call to recalculate whether the instance is valid or not, but I can't find anything in the documentation to support that. Failing that, it's possibly a bug in CRM
Raised a case with Microsoft support, and was given some workaround code:
//Get DynamicPropertyInstance
UpdateProductPropertiesRequest UpdateRequest = new UpdateProductPropertiesRequest();
UpdateRequest.PropertyInstanceList = new EntityCollection();
UpdateRequest.PropertyInstanceList.EntityName = DynamicPropertyInstance.EntityLogicalName;
Entity dpInstance = new Entity(DynamicPropertyInstance.EntityLogicalName, Dpi.Id);
dpInstance.Attributes.Add(nameof(Dpi.ValueString).ToLower(), "Blarg");
dpInstance.Attributes.Add(nameof(Dpi.DynamicPropertyInstanceid).ToLower(), Dpi.Id);
dpInstance.Attributes.Add(nameof(Dpi.RegardingObjectId).ToLower(), new EntityReference(SalesOrderDetail.EntityLogicalName, line.Id));
dpInstance.Attributes.Add(nameof(Dpi.DynamicPropertyId).ToLower(), new EntityReference(DynamicProperty.EntityLogicalName, dpId));
UpdateRequest.PropertyInstanceList.Entities.Add(dpInstance);
crmContext.Execute(UpdateRequest);
Basically, it looks like you have to re-set or re-attach the entities for CRM to pick it up, so this is a workaround for a bug in CRM

Ignore Duplicate Dection Rules in CRM upon Creation of an Account Within Plugin

I'm attempting to create an account within a Qualification Event Plugin. If I am creating an account with a name that matches exactly a name of an existing account, my Duplicate Detection Rule kicks in, and causes an exception to be thrown.
It was my understanding that duplicate detection rules were always warnings, not errors, and by default, you wouldn't get any errors or even notifications when running from a Plugin/SDK call Is this a new change to CRM? Is there a way to ignore Duplicate Detection Rules from a plugin?
Apparently you have to set the "SupressDuplicateDetection" Attribute in the create request:
Entity target = new Entity("account");
target["name"] = "I am a clone";
CreateRequest req = new CreateRequest();
req.Target = target;
req["SuppressDuplicateDetection"] = true;
CreateResponse response = (CreateResponse)_service.Execute(req);
This is intended, and apparently long standing behaviour based on MSDN documentation Run duplicate detection (listed as far back at CRM 2011).
Pass the duplicate detection optional parameter
SuppressDuplicateDetection by adding a value to the Parameters
property of the CreateRequest and UpdateRequest message requests. The
SuppressDuplicateDetection parameter value determines whether the
Create or Update operation can be completed:
true – Create or update the record, if a duplicate is found.
false - Do not create or update the record, if a duplicate is found.
Assuming false is the default as its a bool.
If the duplicate detection optional parameter is set to false and a
duplicate is found, an exception is thrown and the record is not
created or updated.

Updating opportunity when opportunity is won

I've got the task of updating a CRM plugin for a system migrating from cm 2013 to 2016. The plugin fails because it tries to set the opportunity state to won, simply by updating the field. And you need to use the WinOpporunityRequest to do so.
The logic is as follows:
When the opportunity is won the plugin executes and runs on the opportunityclose entity
The plugin creates a new custom entity record (project) and updates several other records.
It gets the current opportunity by using the opportunityid of the opportunityclose entity
It updates a field on the opportunity with a reference to the newly created project record.
That update is done through the Update() method.
On 5 it fails because when at 3 it gets the current opportunity it already has the state of won. And if you try to update the record with a new state it fails.
My question is, how can I get the opportunity when acting on the opportunityclose entity and update only the one single field. I do not need to set the state as this is done in the standard CRM flow.
--Edit
The line of code that fetches the opportunity:
Xrm.Opportunity currentOpportunityObjectToUpdate = serviceContext.CreateQuery<Xrm.Opportunity>().First(x => x.Id == entityRef.Id);
The platform allows you to update closed opportunities, I just tried it to verify. What is the error you are getting?
In step #5, make sure you're only sending the attributes you're trying to update (opportunityid and lookup to project). So, when you issue the update, don't use any preexisting opportunity object that you either retrieved or created...doing so sends all attributes that are on the object and the platform will process each attribute as if it were being changed even if the value is unchanged. Instead, create a new opportunity object with just the id and project specified, something like this:
context.AddObject(new Opportunity() {
Id = idOfOpportunity, // you may have to specify id both here...
OpportunityId = idOfOpportunity, // ...and here, can never remember. Doesn't hurt to specify in both places.
new_ProjectId = idOfProject
});
context.SaveChanges();
If you get stuck, you always have an easy workaround option: take the logic from #4 and move it to an async plugin on create of project (even a workflow should work).

Resources