Automatically trigger a workflow when a record is opened - dynamics-crm-2011

Is there any way to automatically trigger a Custom Workflow Activity every time any Entity's record is opened?

Sure, you could use the ExecuteWorkflow request from some JavaScript that runs on Form Load. Here's an example of calling ExecuteWorkflow from JavaScript.
http://www.mscrmconsultant.com/2013/03/execute-workflow-using-javascript-in.html

If you're wanting to trigger a custom workflow activity, and don't need to do anything workflow related in it, I'd recommend creating a custom action. It is very similar to a workflow, but CRM will create a custom end point for you to call. It eliminates the need to keep track of workflow IDs...

You can use a Plugin instead of Custom Workflow, and register it on the "Retrieve" message.
public void Execute(IServiceProvider serviceProvider)
{
// Obtain the execution context from the service provider.
Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
if (context.Depth == 1)
{
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
// Obtain the target entity from the input parmameters.
EntityReference entity = (EntityReference)context.InputParameters["Target"];
ColumnSet cols = new ColumnSet(
new String[] { "lastname", "firstname", "address1_name" });
var contact = service.Retrieve("contact", entity.Id, cols);
if (contact != null)
{
if (contact.Attributes.Contains("address1_name") == false)
{
Random rndgen = new Random();
contact.Attributes.Add("address1_name", "first time value: " + rndgen.Next().ToString());
}
else
{
contact["address1_name"] = "i already exist";
}
service.Update(contact);
}
}
}
CRM 2011–Retrieve Plugin

Related

How to add customDimensions and set operation_parentId for Azure function log

I created a http trigger V1 azure function on net framework 4.8, and used ILogger for logging. The code is like this.
I checked the Application Insight and queried for traces table. This table contains columns named customDimensions and operation_ParentId. May I ask is there anyway to add custom property in customDimensions column, or set a new Guid value for operation_ParentId? I know that I can use TelemetryClient sdk to create a custom telemetry client for logging. Just curious if there is any easy way which doesn't need to create a new telemetry client, because azure function offers bulit-in integration with application insight.
Also, since azure function runtimes automatically tracks requests, is there any way to change the operation_ParentId and customDimensions for requests table as well? Thanks a lot!
To get both the headers and App Insights to get the custom operation Id, two things must be overridden.
The first is an Activity that wraps the HttpClient, which is responsible for controlling the correlation headers and the other is App Insights' dependency tracing.
Although you can disable Actions completely in your HttpClients, you can just remove the one in the client by setting Activity.Current = null to limit side effects.
var operationId = "CR" + Guid.NewGuid().ToString();
var url = "https://www.microsoft.com";
using (var client = new HttpClient())
{
using (var requestMessage =
new HttpRequestMessage(HttpMethod.Get, url))
{
//Makes the headers configurable
Activity.Current = null;
//set correlation header manually
requestMessage.Headers.Add("Request-Id", operationId);
await client.SendAsync(requestMessage);
}
}
The next step is to remove the App Insights default tracking for this request. Again, you can disable dependency tracking completely, or you can filter out the default telemetry for this request. Processors are registered inside the Startup class just like initializers.
services.AddApplicationInsightsTelemetryProcessor<CustomFilter>();
public class CustomFilter : ITelemetryProcessor
{
private ITelemetryProcessor Next { get; set; }
// next will point to the next TelemetryProcessor in the chain.
public CustomFilter(ITelemetryProcessor next)
{
this.Next = next;
}
public void Process(ITelemetry item)
{
// To filter out an item, return without calling the next processor.
if (!OKtoSend(item)) { return; }
this.Next.Process(item);
}
// Example: replace with your own criteria.
private bool OKtoSend(ITelemetry item)
{
var dependency = item as DependencyTelemetry;
if (dependency == null) return true;
if (dependency.Type == "Http"
&& dependency.Data.Contains("microsoft.com")
//This key is just there to help identify the custom tracking
&& !dependency.Context.GlobalProperties.ContainsKey("keep"))
{
return false;
}
return true;
}
}
Finally, you must inject a telemetry client and call TelemetryClient.TrackDependency() in the method that makes the remote call.
var operationId = "CR" + Guid.NewGuid().ToString();
//setup telemetry client
telemetry.Context.Operation.Id = operationId;
if (!telemetry.Context.GlobalProperties.ContainsKey("keep"))
{
telemetry.Context.GlobalProperties.Add("keep", "true");
}
var startTime = DateTime.UtcNow;
var timer = System.Diagnostics.Stopwatch.StartNew();
//continue setting up context if needed
var url = "https:microsoft.com";
using (var client = new HttpClient())
{
//Makes the headers configurable
Activity.Current = null;
using (var requestMessage =
new HttpRequestMessage(HttpMethod.Get, url))
{
//Makes the headers configurable
Activity.Current = null;
//set header manually
requestMessage.Headers.Add("Request-Id", operationId);
await client.SendAsync(requestMessage);
}
}
//send custom telemetry
telemetry.TrackDependency("Http", url, "myCall", startTime, timer.Elapsed, true);
Refer here more information.
Note: The above is possible by disabling the built-in dependency tracking and App Insights and handling it on your own. But the better approach is let .NET Core & App Insights do the tracking.

Release invoice on new screen

I need your help.
I have created a new screen, where I am calling all invoices pending release.
I have problems to release, I send a message where you request (you want to release).
It shows me the infinite message.
Only once should you ask me, then you should go out and follow the normal process.
public ProcessDocNew()
{
// Acuminator disable once PX1008 LongOperationDelegateSynchronousExecution [Justification]
Document.SetProcessDelegate(
delegate (List<ARInvoice> list)
{
List<ARRegister> newlist = new List<ARRegister>(list.Count);
foreach (ARInvoice doc in list)
{
newlist.Add(doc);
}
ProcessDoc(newlist, true);
}
);
Document.SetProcessCaption(ActionsMensje.Process);
Document.SetProcessAllCaption(ActionsMensje.ProcessAll);
}
public virtual void ProcessDoc(List<ARRegister> list, bool isMassProcess)
{
string title = "Test";
string sms = "¿Stamp?";
var Graph = PXGraph.CreateInstance<ARInvoiceEntry>();
ARInvoice document = Document.Current;
PEFEStampDocument timbrar = new PEFEStampDocument();/*This is a class where it is, all my method*/
if (isMassProcess == true)
{
Document.Ask(title, sms, MessageButtons.YesNo, MessageIcon.Question);
{
PXLongOperation.StartOperation(Graph, delegate
{
timbrar.Stamp(document, Graph); /*here I have my release method*/
});
}
}
}
public static class ActionsMensje
{
public const string Process = "Process";
public const string ProcessAll = "Process All";
}
I await your comments
Only once should you ask me, then you should go out and follow the
normal process.
That is not how the processing pattern works. The process delegate is called for each record and is therefore not a valid location to display a message that should be shown only once.
You would need to add a custom action to achieve that behavior. The scenario you're looking for should be implemented with a processing filter checkbox and processing filter to comply with best practices:
Documentation on processing screens implementation is available here:
https://help-2019r2.acumatica.com/Help?ScreenId=ShowWiki&pageid=a007b57b-af69-4c0f-9fd1-f5d98351035f

How can I fetch an array of data from a custom GI using soap contract based web services

I know how to fetch data from a custom Generic Inquiry using standard soap / page-based web services.
Here's my code for standard web services to get the results from a custom GI:
static void Main(string[] args)
{
GI000081.Screen context = new GI000081.Screen();
context.Url = "http://localhost/AcumaticaDB181000062/(W(6))/Soap/GI000081.asmx";
context.CookieContainer = new System.Net.CookieContainer();
LoginResult loginResult = context.Login("admin", "Passw0rd");
if (loginResult.Code != ErrorCode.OK)
{
throw new Exception(loginResult.Message);
}
GI000081.Content GI000081Content;
GI000081Content = context.GetSchema(); //.IN202500GetSchema();
//Here's the code to obtain the GI data:
string[][] GI000081Data = context.Export
(new Command[] {
GI000081Content.Result.AccountID,
GI000081Content.Result.Address,
GI000081Content.Result.CustomerID,
GI000081Content.Result.AccountName
},
null, //This is the filter - none here, so null..
0,
false,
false
);
}
My request is, can I get an example of C# code for how to do this using the Contract-based web services. I know how to extend the endpoint and get the wsdl file / service reference to my custom Generic Inquiry, but I don't know the syntax to make the actual call.
Thanks in advance...
Just to make sure that you create the entity in the endpoint properly, make sure that the top level entity contain only the Parameters and that it has a sub entity of type details contain all the results. If there is no parameter then it is fine for the top level entity to be empty.
Here is the code sample that I used
class Program
{
static void Main(string[] args)
{
DefaultSoapClient client = new DefaultSoapClient();
client.Login("admin", "admin", null, null, null);
try
{
BatchPaymentsInq batch = new BatchPaymentsInq
{
Result = new BatchPaymentsInqResult[]
{
new BatchPaymentsInqResult { ReturnBehavior = ReturnBehavior.All }
}
};
var result = client.Get(batch);
}
catch(Exception ex)
{
}
finally
{
client.Logout();
}
}
}
Edit:
Here is how I extended my endpoint in order to use it with the Contract Based SOAP API
So the main entity named BatchPaymentsInq is pointing to the Generic Inquiry screen and will not have any field in it as you have mentioned that there is no parameter.
The sub entity Result is an array of BatchPaymentsInqResult an object created for containing the fields in the result grid of the inquiry.

PostEntityImage in update message post-operartion has no key at all

I have registered a plugin for update message of some entity (in post-operation) via CRM tool in Visual Studio and also registered post-image for that plugin like below:
and here is my code :
protected void ExecutePostOpportunityUpdate(LocalPluginContext
localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
// TODO: Implement your custom Plug-in business logic.
IPluginExecutionContext context = localContext.PluginExecutionContext;
Entity postImage = (Entity)context.PostEntityImages["PostImage"];
....
}
But it throws an error and says that there is no key in PostEntityImages at all. I debugged the plugin and saw that there is no key in that at all.
Would you help me please?
Well looking at your code you have to retrieve the actual entity of Opportunity: Try this
try
{
Entity postOpportunityService = (Entity)context.PostEntityImages["PostImage"];
// Opportunity service's parent opportunity lookup reference
EntityReference opportunityReference = (EntityReference)postOpportunityService.Attributes["mpc_opportunityid"];
// Columns to be retrieved for opportunity (aka. columns to be edited)
ColumnSet opportunityColumnSet = new ColumnSet(new string[] { "estimatedvalue", "mpc_estoneoffinvoicing", "mpc_estinvoicingperyear" });
// Retrieve actual opportunity entity
Entity opportunity = service.Retrieve(opportunityReference.LogicalName, opportunityReference.Id, opportunityColumnSet);
}
catch (FaultException<OrganizationServiceFault> ex) { tracingService.Trace("FaultException", ex.ToString()); }

Problem Activating Sharepoint Timer Job

I have created a very simple sharepoint timer job. All i want it to do is iterate through a list and update each list item so that it triggers an existing workflow that works fine. In other words all i am trying to do is work around the limitation that workflows cannot be triggered on a scheduled basis. I have written a class that inherits from SPJobDefinition that does the work and i have a class that inherits from SPFeatureReceiver to install and activate it. I have created the feature using SPVisualdev that my coleagues have used in the past for other SP development.
My Job class is below:
public class DriverSafetyCheckTrigger : SPJobDefinition
{
private string pi_SiteUrl;
public DriverSafetyCheckTrigger(string SiteURL, SPWebApplication WebApp):base("DriverSafetyCheckTrigger",WebApp,null, SPJobLockType.Job)
{
this.Title = "DriverSafetyCheckTrigger";
pi_SiteUrl = SiteURL;
}
public override void Execute(Guid targetInstanceId)
{
using (SPSite siteCollection = new SPSite(pi_SiteUrl))
{
using (SPWeb site = siteCollection.RootWeb)
{
SPList taskList = site.Lists["Driver Safety Check"];
foreach(SPListItem item in taskList.Items)
{
item.Update();
}
}
}
}
}
And the only thing in the feature reciever class is that i have overridden the FeatureActivated method below:
public override void FeatureActivated(SPFeatureReceiverProperties Properties)
{
SPSite site = Properties.Feature.Parent as SPSite;
// Make sure the job isn't already registered.
foreach (SPJobDefinition job in site.WebApplication.JobDefinitions)
{
if (job.Name == "DriverSafetyCheckTrigger")
job.Delete();
}
// Install the job.
DriverSafetyCheckTrigger oDriverSafetyCheckTrigger = new DriverSafetyCheckTrigger(site.Url, site.WebApplication);
SPDailySchedule oSchedule = new SPDailySchedule();
oSchedule.BeginHour = 1;
oDriverSafetyCheckTrigger.Schedule = oSchedule;
oDriverSafetyCheckTrigger.Update();
}
The problem i have is that when i try to activate the feature it throws a NullReferenceException on the line oDriverSafetyCheckTrigger.Update(). I am not sure what is null in this case, the example i have followed for this is this tutorial. I am not sure what I am doing wrong.
I ran your code in a console application and got the following exception when calling .Update()
"DriverSafetyCheckTrigger cannot be deserialized because it does not have a public default constructor"
Maybe that will help?
I have similar code that is working in one of my Feature Receivers:
string jobName = "MyJobDefinition";
foreach (SPJobDefinition job in site.WebApplication.JobDefinitions)
{
if (job.Name == jobName)
{
job.Delete();
}
}
SPDailySchedule schedule = new SPDailySchedule();
schedule.EndHour = 2;
schedule.EndMinute = 59;
schedule.EndSecond = 59;
SPJobDefinition jobDefinition = new MyJobDefinition(jobName, site.WebApplication);
jobDefinition.Schedule = schedule;
jobDefinition.Update();
I wonder if your problem is with the schedule. Try setting BeginMinute and maybe also BeginSecond. You could also try setting the End values in conjunction with or instead of the Begin values.

Resources