Hi FinanceOperation,
I have done this kind of work through plugin, the only issue is that who ever qualify the lead, all the notes in the opportunity will be create by that person.
Below is the full code, you need to register plugin on pre-operation and as sync
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
namespace CopyNotesFromLeadToOpportunity
{
public class CopyNotes : IPlugin
{
public void Execute(IServiceProvider serviceprovider)
{
// Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracing = (ITracingService)serviceprovider.GetService(typeof(ITracingService));
//get execution context from 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);
//Check context contain entity
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
//Check weather the Target entity have the originating lead filed or not
Entity selectedEntity = (Entity)context.InputParameters["Target"];
if (selectedEntity.Attributes.Contains("originatingleadid") == false)
{
return;
}
else
{
EntityReference entLead = (EntityReference)selectedEntity.Attributes["originatingleadid"];
Guid LeadGuid = entLead.Id;
try
{
if (context.MessageName == "Create")
{
#region Get Originatimg Lead Notes and attachment details from Lead Entity
string strFetchNotes = @"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
<entity name='annotation'>
<attribute name='subject' />
<attribute name='notetext' />
<attribute name='documentbody' />
<attribute name='filename' />
<attribute name='annotationid' />
<attribute name='modifiedby' />
<attribute name='modifiedon' />
<order attribute='subject' descending='false' />
<link-entity name='lead' from='leadid' to='objectid' alias='aa'>
<filter type='and'>
<condition attribute='leadid' operator='eq' value='{0}' />
</filter>
</link-entity>
</entity>
</fetch>";
#endregion
strFetchNotes = string.Format(strFetchNotes, LeadGuid);
EntityCollection entNotes = (EntityCollection)service.RetrieveMultiple(new FetchExpression(strFetchNotes));
if (entNotes != null && entNotes.Entities.Count > 0)
{
for (int i = 0; i < entNotes.Entities.Count; i++)
{
Entity entNote = (Entity)entNotes.Entities[i];
// last modified by user
EntityReference modifiedBy = (EntityReference)entNote.Attributes["modifiedby"];
string Modifiedby = modifiedBy.Name;
Guid modifiedByUser = modifiedBy.Id;
// Last modified date of notes (getting time in UTC)
DateTime ModifiedOn = Convert.ToDateTime(entNote.Attributes["modifiedon"].ToString());
// get the time zone of the user who last modified the notes
QueryExpression fetchTimeZone = new QueryExpression()
{
EntityName = "usersettings",
ColumnSet = new ColumnSet("localeid", "timezonecode"),
Criteria =
{
Conditions =
{
new ConditionExpression("systemuserid", ConditionOperator.Equal,modifiedBy.Id)
},
},
};
// Join CRM timezonedefinition with usersettings
LinkEntity linkTimeZoneInfo = new LinkEntity("usersettings", "timezonedefinition", "timezonecode", "timezonecode", JoinOperator.Inner);
linkTimeZoneInfo.Columns = new ColumnSet("standardname");
linkTimeZoneInfo.EntityAlias = "timeZone";
fetchTimeZone.LinkEntities.Add(linkTimeZoneInfo);
DataCollection<Entity> Timezone = service.RetrieveMultiple(fetchTimeZone).Entities;
//get the timezone of the user
string timeZoneOfUser = ((Microsoft.Xrm.Sdk.AliasedValue)(Timezone[0].Attributes["timeZone.standardname"])).Value.ToString();
// convert UTC time to User time
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById(timeZoneOfUser);
DateTime userConvertedTime = TimeZoneInfo.ConvertTimeFromUtc(ModifiedOn, tz);
string modifiedDateTime = userConvertedTime.ToString("MM/dd/yy H:mm:ss tt") + " " + ("(" + timeZoneOfUser + ")");
//string modifiedDateTime = userConvertedTime.ToString("MM/dd/yy H:mm:ss tt");
#region Creating new Notes record from Existing Notes Record
//array to remove from notes record
string[] strAttributesNotestoRemove = new string[] { "createdon", "createdby", "modifiedon", "modifiedby", "annotationid", "objecttypecode", "objectid" };
//Clone new notes object from existing notes record
Entity entNewAnnotation = CloneRecordForEntity("annotation", entNote, strAttributesNotestoRemove);
//Add object id to attach this new notes to Invoice sponsor item record
entNewAnnotation["objectid"] = new EntityReference(context.PrimaryEntityName, context.PrimaryEntityId);
entNewAnnotation["objecttypecode"] = context.PrimaryEntityName;
entNewAnnotation["notetext"] = entNote.GetAttributeValue<string>("notetext") + "\r\n" + "Lead Note By : " + Modifiedby + "\r\n" + "Lead Note On : " + modifiedDateTime;
service.Create(entNewAnnotation);
#endregion
}//End for notes count
}//End entities count
}//End of create contex
}
catch (Exception ex)
{
tracing.Trace("Exception : " + ex.Message);
throw new InvalidPluginExecutionException(ex.Message.ToString());
}
}
}
}
#region Clone Record
/// <summary>
/// Creates Cloned copy of soure entity for the given entity object
/// </summary>
/// <param name="targetEntityName">Schemaname of the cloned copy target entity</param>
/// <param name="sourceEntity">Entity object of the record to be Cloned</param>
/// <param name="strAttributestoRemove">Array of records not to include in the cloned copy</param>
/// <returns>Entity object (Cloned Copy)</returns>
private Entity CloneRecordForEntity(string targetEntityName, Entity sourceEntity, string[] strAttributestoRemove)
{
//Initiate target entity (cloned copy)
Entity clonedEntity = new Entity(targetEntityName);
//read the attributes from source entity
AttributeCollection attributeKeys = sourceEntity.Attributes;
//Loop through each of the key and check and add that in the target entity
foreach (string key in attributeKeys.Keys)
{
//Check if key is not there in the list of removed keys
if (Array.IndexOf(strAttributestoRemove, key) == -1)
{
//add key from source in the destination
clonedEntity[key] = sourceEntity[key];
} //end if checking removed attributes
}//end foreach keys
return clonedEntity;
}
#endregion
}
}
Mark My answer as verified if it helps,
Thanks,
Shahbaaz