Need to calculate record Age and record Total Age field with the use of enhanced SLA in Microsoft dynamics CRM 2016 - dynamics-crm-online

I have a requirement to calculate a record and record total age with the use of enhanced SLA. Is it possible?
Age : A record has a StartDate field and the value of StartDate is 1st March 2016 and there is another field named as EndDate and the value of EndDate is 31st March 2016, and the service getting hold for 3 days in this period, so the Age will be : 31 - 3 = 28
Total Age : Same as per above example but the difference is we does not need to include the hold days, So the Total Age will be : 31.
Thanks,

I found this interesting blog post by Aileen Gusni here
Intercept Column/Field Value in CRM View using RetrieveMultiple Plugin C#
Basically she creates a new field (in the example below it is pa_age), but she doesn't add it to the form or anything
Instead she catches the Retrieve and RetrieveMultiple messages in a Plugin and calculates this field as required.
I've pasted her code below
Note this is not my code, it was written by Aileen
public void Execute(IServiceProvider serviceProvider)
{
#region must to have
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
// Create service with context of current user
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
//create tracing service
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
#endregion
//this is to modify the Age column
if (context.OutputParameters.Contains("BusinessEntityCollection"))
{
var retrievedResult = (EntityCollection)context.OutputParameters["BusinessEntityCollection"];
foreach (Entity entity in retrievedResult.Entities)
{
if (entity.Contains("birthdate"))
{
var birthday = entity.GetAttributeValue<DateTime>("birthdate");
int age = CalculateAgeYear(birthday);
//modify the Age field
entity.Attributes["pa_age"] = age;
}
}
}
}
There are a few things to consider with this approach:
The pa_age field's value never gets set. It is added to the entity only so that it can be included in the view
this means that the pa_age field can't be included on the form or in reports because it will always be null
you can't use the pa_age field in advanced finds (filter), but of course you can add it to the advanced find results. The reason for this is the same as before: the value isn't actually saved in the database
Her blog post has much more information and screenshots of how it all works. I haven't tried this approach but it might be useful for you

Related

Dynamics 365 API link between ActivityPointer and activitytypecode global option set

I am reading data from the ActivityPointer entity in Dynamics 365 via the API and I want to link the activitytypecode field value to the activitypointer_activitytypecode global option set, which I believe is the correct one. However the values don't seem to match. In the ActivityPointer.activitytypecode field I have values such as:
phonecall
bulkoperation
email
appointment
task
But those values don't appear in the option set definition, using this query: GlobalOptionSetDefinitions(Name='activitypointer_activitytypecode')
The option set has the code values (e.g. 4202 for Email) and the different descriptions in all languages, but nothing matches back to the values on ActivityPointer
Optionset is just key value pairs (4202: Email and so on), If you want to get the formatted text value of optionset (Email, Fax, etc) from your web api query results - then you have to use activitytypecode#OData.Community.Display.V1.FormattedValue to get it. Read more
I recommend this article for complete understanding of CRM activities.
If you are looking for the code integer value in your resultset, that seems to be an issue and the result is not the expected one - old SO thread
The problem is that if you are reading activitytypecode in code, then you will know that you get a string value. This is the logical name of the activity entity, e.g. "email", "phonecall" etc.
If you look at the definition of activitytypecode in Power Apps then it shows it as "Entity name" (i.e. text) but using the classic solution editor it shows as the global activitypointer_activitytypecode option set, which contains values for "Email", "Phone Call" etc.
I am sure that there should be a simple way of converting from activitytypecode (i.e. entity name) to activitypointer_activitytypecode (i.e. option set), but I've yet to find it.
What I am doing is retrieving the global activitypointer_activitytypecode option set, so I have access to all of the text values. Then retrieve details about the entity indicated by activitytypecode, specifically what is of interesting is the display name. Then loop through the option set looking for a case-insensitive match on display name.
This is my C# code:
public int? GetActivityType(IOrganizationService service, string activityTypeCode)
{
// Get all activity types.
var optionSetRequest = new RetrieveOptionSetRequest()
{
Name = "activitypointer_activitytypecode"
};
var optionSetResponse = (RetrieveOptionSetResponse)service.Execute(optionSetRequest);
var optionSetMetadata = (OptionSetMetadata)optionSetResponse.OptionSetMetadata;
var optionValues = new Dictionary<string, int?>(StringComparer.OrdinalIgnoreCase);
foreach (var option in optionSetMetadata.Options)
{
foreach (var optionLabel in option.Label.LocalizedLabels)
{
optionValues[optionLabel.Label] = option.Value;
}
}
// Get the display name for the activity.
var retrieveEntityRequest = new RetrieveEntityRequest
{
EntityFilters = EntityFilters.Entity,
LogicalName = activityTypeCode
};
var retrieveEntityResponse = (RetrieveEntityResponse)service.Execute(retrieveEntityRequest);
LocalizedLabelCollection entityLabels = retrieveEntityResponse.EntityMetadata.DisplayName.LocalizedLabels;
// Look up the display name in the option set values.
foreach (var entityLabel in entityLabels)
{
if (optionValues.TryGetValue(entityLabel.Label, out int? value))
{
return (Schema.GlobalOptionSet.ActivityType?)value;
}
}
// If we get here then we've failed.
return null;
}
That is making two API calls, so best avoided in any situations where performance might be an issue. I'm not saying the code is perfect, but it hasn't let me down yet. Even so, I would recommend making do with the logical names provided by activitytypecode if you can.

Access ProcessId and StageId in Dynamics CRM Plugin

I'm writing a plugin on Campaign which used a Business Process Flow. The fields ProcessId and StageId which are created by the Business Process Flow in Campaign Entity. I need to retrieve these values for a record in my plugin.
They don't appear in the Plugin Registration Tool's Step Image. They don't even appear in CRM workflows were I can populate them in some other field.
Is there a good alternative on how I can achieve this?
Why not just grab a service from your IServiceProvider, and retrieve the fields?
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = CommonPluginLibrary.GetContextFromIServiceProvider(serviceProvider);
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
Entity campaign = service.Retrieve(context.PrimaryEntityId, context.PrimaryEntityName, new ColumnSet("processid", "stageid"));
// ...
// Do your stuff with campaign["processid"], campaign["stageid"]
// ...
}
Another approach would be creating two shadow fields for stageid and processid (e.g. new_stageid, new_processid), and populating these fields using a synchronous workflow that triggers on process/stage update.
Then, you could register your plug-in on these shadow fields as they would be your entity's custom attributes.
You should be able to retrieve this by passing the correct input parameters to a workflow activity in this business process flow.
1) if you have these string inputs:
[RequiredArgument]
[Input("Process Name")]
public InArgument Process { get; set; }
[RequiredArgument]
[Input("Process Stage Name")]
public InArgument ProcessStage { get; set; }
2) Execute code Get Process:
using (var _context= new OrganizationServiceContext(service))
{
// Get the processid using the name provided
var process = (from p in _context.CreateQuery()
where
p.Name == Process.Get(executionContext)
&&
p.StateCode == WorkflowState.Activated
select new Workflow
{WorkflowId = p.WorkflowId}
).FirstOrDefault();
if (process==null)
throw new InvalidPluginExecutionException(string.Format("Process '{0}' not found",Process.Get(executionContext)));
Get the stage id using the name provided
var stage = (from s in _context.CreateQuery()
where
s.StageName == ProcessStage.Get(executionContext)
&&
s.ProcessId.Id == process.WorkflowId
select new ProcessStage
{ProcessStageId = s.ProcessStageId}
).FirstOrDefault();
if (stage == null)
throw new InvalidPluginExecutionException(string.Format("Stage '{0}' not found", Process.Get(executionContext)));
You can now Change Update the stage with your values retrieved ...
Entity uStage = new Entity(context.PrimaryEntityName);
uStage.Id = context.PrimaryEntityId; //
uStage["stageid"] = stage.ProcessStageId; //retrieved stage
uStage["processid"] = process.WorkflowId; //process id
To access process and stage ids you can use processid and stageid fields of record. I'm pretty sure that you can get it from Images or through direct read of a record. Additionally you can recheck following article:
https://deepakexploring.wordpress.com/tag/updating-process-id-in-crm-2013/

Business Process Error: Dynamics CRM and Visual Studio

I have written a C# plugin for post update of the parent record based on the multiple fields.
In this I am trying to calculate the total value in the parent entity based on the values updated in the child entity, which has rate and units fields in it. So basically, total=rate*unit. The code builds fine, but when creating a new form in dynamics crm it genetrates a Business Process Error: Unexpected exception from plug-in (Execute): Parentchild1.parentchildpluginSystem.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
Here is my code:
namespace Parentchild1
{
public class parentchildplugin : IPlugin
{
private Entity abcevent_parent;
public void Execute(IServiceProvider serviceProvider)
{
// Obtain the execution context from the service provider.
IPluginExecutionContext context =
(IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
// Get a reference to the Organization service.
IOrganizationServiceFactory factory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
if (context.InputParameters != null)
{
//entity = (Entity)context.InputParameters["Target"];
//Instead of getting entity from Target, we use the Image
Entity entity = context.PostEntityImages["PostImage"];
Money rate = (Money)entity.Attributes["abcevent_rate"];
int unit = (int)entity.Attributes["abcevent_unit"];
// EntityReference parent = (EntityReference)entity.Attributes["abcevent_parentid"];
//Multiply
// Money total = new Money(rate.Value * units);
//Set the update entity
Entity parententity = new Entity("abcevent_parent");
//parententity.Id = parent.Id;
//parententity.Attributes["abcevent_total"] = total;
// abcevent_parentid = Guid IOrganizationservice.Create(Entity parentid);
Guid parentGuid = service.Create(abcevent_parent);
EntityReference parent = (EntityReference)entity.Attributes["abcevent_parentid"];
Money total = new Money(rate.Value * unit);
//Update
//service.Update(parententity);
}
the problem you ask for:
The given key was not present in the dictionary.
It is because one key is not in the list, if you try to get an attribute like
int number = (int)entity.Attributes["random_attribute"]
This throws the error, because random_attribute it is not in the context.
You have to make sure the attribute is in the context... the best practice to this is asking for a Contains:
if (entity.Contains("random_attribute"))
This way you know you can safely access to the attribute.
Another reason may be the Image, make sure it is in the context.

Telerik OpenAccess - Search With Non-Persistent Property

I'm using Telerik OpenAccess and SQL Server on a project and I need to be able to search by what someone's age will be on a certain date. The problem that I am running into is that the person's date of birth is stored in one table and the date to compare to is in another table, which prevents me from using a computed column. They are, however, joined together so that I can calculate the age by creating my own non-persistent property in the partial class like so:
public partial class Student
{
[Telerik.OpenAccess.Transient]
private int? _ageUponArrival;
public virtual int? AgeUponArrival
{
get
{
try
{
var dob = DateTime.Parse(this.StudentProfiles.First().Person.YearOfBirth);
var programStart = (DateTime)(this.StudentPrograms.First().ProgramStart);
this._ageUponArrival = programStart.Year - dob.Year;
if (dob > programStart.AddYears(-(int)(this._ageUponArrival)))
{
(this._ageUponArrival)--;
}
}
catch (Exception e)
{
this._ageUponArrival = null;
}
return _ageUponArrival;
}
set { }
}
}
Please ignore how bad the tables are set up, it's something that I inherited and can't change at this point. The problem with this approach is that the property is not available to search on with Linq. I know that I could create a view that would do this for me, but I would much rather not have to maintain a view just for this. Is there any way at all to create a calculated property through Telerik that would be calculated on the db server in such a way as to be searchable?
It appears that this is not possible at this point. http://www.telerik.com/community/forums/orm/linq-questions/dynamic-query-with-extended-field.aspx

Find items is SSRS by Id

How do you find items in SSRS by ID? I tried to use the id returned by another find result, a new guid to string and small random string all of which return the same error:
The ID field has a value that is not valid. ---> Microsoft.ReportingServices.Diagnostics.Utilities.InvalidElementException: The ID field has a value that is not valid.
Here is the code:
var request = new FindItemsRequest
{
Conditions = new[] { new SearchCondition { Name = "ID", Value = "test"} },
Folder = "/"
};
return _ssrsService
.FindItems(request)
.Items
I'm using SSRS 2005.
Pretty sure this can't be done through the SSRS service. Ended up finding all objects then using LINQ to filter down to the ID I need.
The MS documentation on the FindItems method says:
Applications that use FindItems typically accept user input for specific properties and property values. The searchable properties are Name, Description, CreatedBy, CreationDate, ModifiedBy, and ModifiedDate. The items that are returned are only those for which a user has Read Properties permission.

Resources