diff --git a/.vs/Dynamics-365-Workflow-Tools/v15/.suo b/.vs/Dynamics-365-Workflow-Tools/v15/.suo index 01557ee..0e07145 100644 Binary files a/.vs/Dynamics-365-Workflow-Tools/v15/.suo and b/.vs/Dynamics-365-Workflow-Tools/v15/.suo differ diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json index c8ea26a..448f359 100644 --- a/.vs/VSWorkspaceState.json +++ b/.vs/VSWorkspaceState.json @@ -5,6 +5,6 @@ "\\msdyncrmWorkflowTools\\msdyncrmWorkflowTools_Class", "\\msdyncrmWorkflowTools\\msdyncrmWorkflowTools_ConsoleTest" ], - "SelectedNode": "\\msdyncrmWorkflowTools\\msdyncrmWorkflowTools_Class\\msdyncrmWorkflowTools_Class.cs", + "SelectedNode": "\\msdyncrmWorkflowTools\\msdyncrmWorkflowTools.sln", "PreviewInSolutionExplorer": false } \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite index 81c93a4..a6dfbe0 100644 Binary files a/.vs/slnx.sqlite and b/.vs/slnx.sqlite differ diff --git a/msdyncrmWorkflowTools/.vs/msdyncrmWorkflowTools/v15/.suo b/msdyncrmWorkflowTools/.vs/msdyncrmWorkflowTools/v15/.suo index e8faec3..2a4866b 100644 Binary files a/msdyncrmWorkflowTools/.vs/msdyncrmWorkflowTools/v15/.suo and b/msdyncrmWorkflowTools/.vs/msdyncrmWorkflowTools/v15/.suo differ diff --git a/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Class/MapMultiSelectOptionSet.cs b/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Class/MapMultiSelectOptionSet.cs index 0595f1e..694a293 100644 --- a/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Class/MapMultiSelectOptionSet.cs +++ b/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Class/MapMultiSelectOptionSet.cs @@ -26,6 +26,14 @@ public class MapMultiSelectOptionSet : CodeActivity [Input("Target Attributes")] public InArgument TargetAttributes { get; set; } + /// + /// Indicate if the existing selected values in the target multi-select optionset attributes will be maintained. + /// By default, it will remove the existing values and assign the new ones given by the argument "AttributesValues" + /// + [Input("Keep Existing Values")] + [Default("false")] + public InArgument KeepExistingValues { get; set; } + protected override void Execute(CodeActivityContext executionContext) { Common objCommon = new Common(executionContext); @@ -35,7 +43,7 @@ protected override void Execute(CodeActivityContext executionContext) string[] targetAttributes = GetTargetAttributes(executionContext, objCommon.tracingService); EntityReference sourceEntityReference = GetSourceEntityReference(executionContext, objCommon.service); EntityReference targetEntityReference = GetTargetEntityReference(executionContext, objCommon.service); - Entity targetEntity = BuildTargetEntity(sourceEntityReference, targetEntityReference, sourceAttributes, targetAttributes,objCommon.tracingService,objCommon.service); + Entity targetEntity = BuildTargetEntity(sourceEntityReference, targetEntityReference, sourceAttributes, targetAttributes,objCommon.tracingService,objCommon.service, executionContext); if (targetEntity != null) { @@ -88,7 +96,7 @@ private string[] GetTargetAttributes(CodeActivityContext executionContext, ITrac return targetAttributesArray; } - private Entity BuildTargetEntity(EntityReference sourceEntityReference, EntityReference targetEntityReference, string[] sourceAttributes, string[] targetAttributes, ITracingService tracingService, IOrganizationService organizationService) + private Entity BuildTargetEntity(EntityReference sourceEntityReference, EntityReference targetEntityReference, string[] sourceAttributes, string[] targetAttributes, ITracingService tracingService, IOrganizationService organizationService, CodeActivityContext executionContext) { if (sourceEntityReference == null || targetEntityReference == null || sourceAttributes == null || targetAttributes == null) return null; @@ -107,17 +115,22 @@ private Entity BuildTargetEntity(EntityReference sourceEntityReference, EntityRe Entity targetEntity = new Entity(targetEntityReference.LogicalName, targetEntityReference.Id); string targetAttribute = null; int attributeMappedCounter = 0; + + OptionSetValueCollection sourceNewValues = null; + OptionSetValueCollection targetExistingValues = null; + + for (int i = 0; i < numberSourceAttribute; i++) { string sourceAttribute = sourceAttributes[i]; if (sourceEntity.Contains(sourceAttribute)) { - var optionSetValueCollection = sourceEntity[sourceAttribute] as OptionSetValueCollection; - if (typeof(OptionSetValueCollection).Equals(optionSetValueCollection.GetType())) + sourceNewValues = sourceEntity[sourceAttribute] as OptionSetValueCollection; + if (typeof(OptionSetValueCollection).Equals(sourceNewValues.GetType())) { targetAttribute = targetAttributes[i]; - targetEntity.Attributes.Add(targetAttribute, optionSetValueCollection); - tracingService.Trace("Source attribute '{0}' has been mapped to target attribute {1}. ", sourceAttribute, targetAttribute); + targetExistingValues = GetExistingAttributeValues(targetEntity.ToEntityReference(), targetAttribute, tracingService, organizationService, executionContext); + targetEntity.Attributes.Add(targetAttribute, MergeOptionSetCollections(sourceNewValues, targetExistingValues,tracingService)); attributeMappedCounter++; } else @@ -132,5 +145,47 @@ private Entity BuildTargetEntity(EntityReference sourceEntityReference, EntityRe return targetEntity; } + private OptionSetValueCollection GetExistingAttributeValues(EntityReference targetEntityReference, string attributeName, ITracingService tracingService, IOrganizationService organizationService, CodeActivityContext executionContext) + { + tracingService.Trace("Retrieving existing values"); + + Boolean attributeValues = KeepExistingValues.Get(executionContext); + + if (attributeValues == false) + return null; + + Entity record = organizationService.Retrieve(targetEntityReference.LogicalName, targetEntityReference.Id, new ColumnSet(new string[] { attributeName })); + + tracingService.Trace("Existing values have been retrieved correctly"); + + if (record.Contains(attributeName)) + return record[attributeName] as OptionSetValueCollection; + else + return null; + } + + private OptionSetValueCollection MergeOptionSetCollections(OptionSetValueCollection newValues, OptionSetValueCollection existingValues, ITracingService tracingService) + { + tracingService.Trace("Merging new and exiting multi-select optionset values"); + + if (existingValues == null && newValues == null) + return new OptionSetValueCollection(); + + if (existingValues == null) + return newValues; + + if (newValues == null) + return existingValues; + + foreach (OptionSetValue newValue in newValues) + { + if (!existingValues.Contains(newValue)) + existingValues.Add(newValue); + } + + tracingService.Trace("New and exiting multi-select optionset values have been merged correctly. Total options: {0} ", existingValues.Count); + return existingValues; + } + } } diff --git a/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Class/SetMultiSelectOptionSet.cs b/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Class/SetMultiSelectOptionSet.cs index 62da292..59c45a5 100644 --- a/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Class/SetMultiSelectOptionSet.cs +++ b/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Class/SetMultiSelectOptionSet.cs @@ -25,6 +25,13 @@ public class SetMultiSelectOptionSet : CodeActivity [RequiredArgument] [Input("Attribute Values")] public InArgument AttributeValues { get; set; } + /// + /// Indicate if the existing selected values in the target multi-select optionset attribute will be maintained. + /// By default, it will remove the existing values and assign the new ones given by the argument "AttributesValues" + /// + [Input("Keep Existing Values")] + [Default("false")] + public InArgument KeepExistingValues { get; set; } protected override void Execute(CodeActivityContext executionContext) { @@ -33,9 +40,13 @@ protected override void Execute(CodeActivityContext executionContext) EntityReference sourceEntityReference = GetTargeteEntityReference(executionContext,objCommon.tracingService, objCommon.service); string attributeName = GetAttributeName(executionContext,objCommon.tracingService); - OptionSetValueCollection values = GetAttributeValues(executionContext,objCommon.tracingService); + OptionSetValueCollection newValues = GetNewAttributeValues(executionContext, objCommon.tracingService); + OptionSetValueCollection existingValues = GetExistingAttributeValues(sourceEntityReference, attributeName,executionContext, objCommon.tracingService, objCommon.service); + + + //UpdateRecord(sourceEntityReference, attributeName, values,objCommon.service,objCommon.tracingService); + UpdateRecord(sourceEntityReference, attributeName, newValues, existingValues, objCommon.service, objCommon.tracingService); - UpdateRecord(sourceEntityReference, attributeName, values,objCommon.service,objCommon.tracingService); } private EntityReference GetTargeteEntityReference(CodeActivityContext executionContext, ITracingService tracingService, IOrganizationService organizationService) @@ -53,7 +64,9 @@ private string GetAttributeName(CodeActivityContext executionContext, ITracingSe return attributeName; } - private OptionSetValueCollection GetAttributeValues(CodeActivityContext executionContext, ITracingService tracingService) + //private OptionSetValueCollection GetAttributeValues(CodeActivityContext executionContext, ITracingService tracingService) + private OptionSetValueCollection GetNewAttributeValues(CodeActivityContext executionContext, ITracingService tracingService) + { string attributeValues = AttributeValues.Get(executionContext) ?? throw new ArgumentNullException("Attribute Values is empty"); tracingService.Trace("Attribute Values:'{0}'", attributeValues); @@ -90,18 +103,63 @@ private OptionSetValueCollection GetAttributeValues(CodeActivityContext executio return optionSetValueCollection; } + private OptionSetValueCollection GetExistingAttributeValues(EntityReference targetEntityReference, string attributeName, CodeActivityContext executionContext, ITracingService tracingService, IOrganizationService organizationService) + { + tracingService.Trace("Retrieving existing values"); + + Boolean attributeValues = KeepExistingValues.Get(executionContext); + + if (attributeValues == false) + return null; + + Entity record = organizationService.Retrieve(targetEntityReference.LogicalName, targetEntityReference.Id, new ColumnSet(new string[] { attributeName })); + + tracingService.Trace("Existing values have been retrieved correctly"); + + if (record.Contains(attributeName)) + return record[attributeName] as OptionSetValueCollection; + else + return null; + } + + + //private void UpdateRecord(EntityReference targetEntityReference, string attributeName, OptionSetValueCollection values, IOrganizationService organizationService, ITracingService tracingService) + private void UpdateRecord(EntityReference targetEntityReference, string attributeName, OptionSetValueCollection newValues, OptionSetValueCollection existingValues, IOrganizationService organizationService, ITracingService tracingService) - private void UpdateRecord(EntityReference targetEntityReference, string attributeName, OptionSetValueCollection values, IOrganizationService organizationService, ITracingService tracingService) { - if (targetEntityReference == null || attributeName == null || values == null) - throw new ArgumentNullException(string.Format("Unexpected null parameters when trying to update record. Record reference '{0}' - attibute name '{1}' - values '{2}'", targetEntityReference, attributeName, values)); + if (targetEntityReference == null || attributeName == null || newValues == null) + throw new ArgumentNullException(string.Format("Unexpected null parameters when trying to update record. Record reference '{0}' - attibute name '{1}' - values '{2}'", targetEntityReference, attributeName, newValues)); + Entity targetEntity = new Entity(targetEntityReference.LogicalName, targetEntityReference.Id); - targetEntity[attributeName] = values; + targetEntity[attributeName] = MergeOptionSetCollections(newValues, existingValues, tracingService); organizationService.Update(targetEntity); tracingService.Trace("Multi-select option set attribute '{0}' has been updated correctly for the record type '{1}' with id '{2}'", attributeName, targetEntityReference.LogicalName, targetEntityReference.Id); } + private OptionSetValueCollection MergeOptionSetCollections(OptionSetValueCollection newValues, OptionSetValueCollection existingValues, ITracingService tracingService) + { + tracingService.Trace("Merging new and exiting multi-select optionset values"); + + if (existingValues == null && newValues == null) + return new OptionSetValueCollection(); + + if (existingValues == null) + return newValues; + + if (newValues == null) + return existingValues; + + foreach (OptionSetValue newValue in newValues) + { + if (!existingValues.Contains(newValue)) + existingValues.Add(newValue); + } + + tracingService.Trace("New and exiting multi-select optionset values have been merged correctly. Total options: {0} ", existingValues.Count); + return existingValues; + } + } } diff --git a/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Properties/AssemblyInfo.cs b/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Properties/AssemblyInfo.cs index 4149177..7517d9f 100644 --- a/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Properties/AssemblyInfo.cs +++ b/msdyncrmWorkflowTools/msdyncrmWorkflowTools/Properties/AssemblyInfo.cs @@ -33,5 +33,5 @@ // Puede especificar todos los valores o usar los valores predeterminados (número de compilación y de revisión) // usando el símbolo '*' como se muestra a continuación: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.54.0")] -[assembly: AssemblyFileVersion("1.0.54.0")] +[assembly: AssemblyVersion("1.0.54.1")] +[assembly: AssemblyFileVersion("1.0.54.1")] diff --git a/msdyncrmWorkflowTools/msdyncrmWorkflowTools/msdyncrmWorkflowTools.csproj b/msdyncrmWorkflowTools/msdyncrmWorkflowTools/msdyncrmWorkflowTools.csproj index b9f288f..8dd391d 100644 --- a/msdyncrmWorkflowTools/msdyncrmWorkflowTools/msdyncrmWorkflowTools.csproj +++ b/msdyncrmWorkflowTools/msdyncrmWorkflowTools/msdyncrmWorkflowTools.csproj @@ -49,7 +49,7 @@ False - ..\..\..\..\..\Tools\PluginRegistration\Microsoft.Crm.Sdk.Proxy.dll + ..\..\..\..\..\..\..\Devtools\Tools\PluginRegistration\Microsoft.Crm.Sdk.Proxy.dll diff --git a/msdyncrmWorkflowTools/msdyncrmWorkflowTools_Class/msdyncrmWorkflowTools_Class.csproj b/msdyncrmWorkflowTools/msdyncrmWorkflowTools_Class/msdyncrmWorkflowTools_Class.csproj index 7f7587c..3e0d7a5 100644 --- a/msdyncrmWorkflowTools/msdyncrmWorkflowTools_Class/msdyncrmWorkflowTools_Class.csproj +++ b/msdyncrmWorkflowTools/msdyncrmWorkflowTools_Class/msdyncrmWorkflowTools_Class.csproj @@ -37,17 +37,17 @@ False - ..\..\..\..\..\Tools\PluginRegistration\Microsoft.Crm.Sdk.Proxy.dll + ..\..\..\..\..\..\..\Devtools\Tools\PluginRegistration\Microsoft.Crm.Sdk.Proxy.dll ..\packages\Microsoft.IdentityModel.6.1.7600.16394\lib\net35\Microsoft.IdentityModel.dll True - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.5\lib\net452\Microsoft.Xrm.Sdk.dll + ..\..\..\..\..\..\..\Devtools\Tools\PluginRegistration\Microsoft.Xrm.Sdk.dll - ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.5\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll + ..\..\..\..\..\..\..\Devtools\Tools\PluginRegistration\Microsoft.Xrm.Sdk.Workflow.dll ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll diff --git a/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/App.config b/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/App.config index 6ed82b5..fd5ef8e 100644 --- a/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/App.config +++ b/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/App.config @@ -25,6 +25,10 @@ + + + + diff --git a/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/msdyncrmWorkflowTools_ConsoleTest.csproj b/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/msdyncrmWorkflowTools_ConsoleTest.csproj index ed76dee..472c224 100644 --- a/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/msdyncrmWorkflowTools_ConsoleTest.csproj +++ b/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/msdyncrmWorkflowTools_ConsoleTest.csproj @@ -40,7 +40,7 @@ False - ..\..\..\..\..\Tools\PluginRegistration\Microsoft.Crm.Sdk.Proxy.dll + ..\..\..\..\..\..\..\Devtools\Tools\PluginRegistration\Microsoft.Crm.Sdk.Proxy.dll ..\packages\Microsoft.IdentityModel.6.1.7600.16394\lib\net35\Microsoft.IdentityModel.dll @@ -52,21 +52,21 @@ ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.28.3\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll - - ..\packages\Microsoft.CrmSdk.XrmTooling.CoreAssembly.9.0.2.7\lib\net452\Microsoft.Rest.ClientRuntime.dll + + ..\packages\Microsoft.Rest.ClientRuntime.2.3.18\lib\net452\Microsoft.Rest.ClientRuntime.dll - ..\packages\Microsoft.CrmSdk.CoreAssemblies.9.0.2.5\lib\net452\Microsoft.Xrm.Sdk.dll + ..\..\..\..\..\..\..\Devtools\Tools\PluginRegistration\Microsoft.Xrm.Sdk.dll - ..\packages\Microsoft.CrmSdk.Deployment.9.0.2.5\lib\net452\Microsoft.Xrm.Sdk.Deployment.dll + ..\..\..\..\..\..\..\Devtools\Tools\CoreTools\Microsoft.Xrm.Sdk.Deployment.dll - ..\packages\Microsoft.CrmSdk.Workflow.9.0.2.5\lib\net452\Microsoft.Xrm.Sdk.Workflow.dll + ..\..\..\..\..\..\..\Devtools\Tools\PluginRegistration\Microsoft.Xrm.Sdk.Workflow.dll False - ..\..\..\..\..\Tools\PluginRegistration\Microsoft.Xrm.Tooling.Connector.dll + ..\..\..\..\..\..\..\Devtools\Tools\PluginRegistration\Microsoft.Xrm.Tooling.Connector.dll ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll @@ -80,6 +80,9 @@ + + + diff --git a/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/packages.config b/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/packages.config index a351cc0..74dee46 100644 --- a/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/packages.config +++ b/msdyncrmWorkflowTools/msdyncrmWorkflowTools_ConsoleTest/packages.config @@ -6,5 +6,6 @@ + \ No newline at end of file diff --git a/msdyncrmWorkflowTools/msdyncrmWorkflowTools_Tests/msdyncrmWorkflowTools_Tests.csproj b/msdyncrmWorkflowTools/msdyncrmWorkflowTools_Tests/msdyncrmWorkflowTools_Tests.csproj index e2a81a2..295f3f7 100644 --- a/msdyncrmWorkflowTools/msdyncrmWorkflowTools_Tests/msdyncrmWorkflowTools_Tests.csproj +++ b/msdyncrmWorkflowTools/msdyncrmWorkflowTools_Tests/msdyncrmWorkflowTools_Tests.csproj @@ -40,7 +40,7 @@ False - ..\..\..\..\..\Tools\PluginRegistration\Microsoft.Crm.Sdk.Proxy.dll + ..\..\..\..\..\..\..\Devtools\Tools\PluginRegistration\Microsoft.Crm.Sdk.Proxy.dll ..\packages\Microsoft.IdentityModel.6.1.7600.16394\lib\net35\Microsoft.IdentityModel.dll