Skip to content

Commit

Permalink
ADD Entity Tools >GUID to Incident
Browse files Browse the repository at this point in the history
ADD Entity Tools > GUID to Theme
ADD FetchXML Tools > Execute Action
ADD FetchXML Tools > Execute Workflow
ADD FetchXML Tools > Find Task
  • Loading branch information
ZooY committed Nov 11, 2020
1 parent 52887db commit d9a1f07
Show file tree
Hide file tree
Showing 12 changed files with 401 additions and 113 deletions.
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ Workflow
<td>Действие возвращает сущность "Факс" (fax) для указанного GUID.</td>
</tr>
<tr>
<td>:new: GUID to Incident</td>
<td>Действие возвращает сущность "Обращение" (incident) для указанного GUID.</td>
</tr>
<tr>
<td>GUID to Invoice</td>
<td> Действие возвращает сущности "Счет" (invoice) и "Продукт счета" (invoicedetail) для указанного GUID.</td>
</tr>
Expand Down Expand Up @@ -241,6 +245,10 @@ Workflow
<td>Действие возвращает сущность "Группа пользователей" (team) для указанного GUID.</td>
</tr>
<tr>
<td>:new: GUID to Theme</td>
<td>Действие возвращает сущность "Тема" (theme) для указанного GUID.</td>
</tr>
<tr>
<td>GUID to User</td>
<td>Действие возвращает сущность "Пользователь" (systemuser) для указанного GUID.</td>
</tr>
Expand Down Expand Up @@ -282,10 +290,22 @@ Workflow
<td>Удаление записей, найденных с помощью запроса FetchXML.</td>
</tr>
<tr>
<td>:new: <a href="https://github.com/ZooY/Dynamics365.Tools/wiki/FetchXML-Tools#entity-as-json">Entity as JSON</a></td>
<td><a href="https://github.com/ZooY/Dynamics365.Tools/wiki/FetchXML-Tools#entity-as-json">Entity as JSON</a></td>
<td>Получение сущности в виде строки в формате JSON.</td>
</tr>
<tr>
<td>:new: Execute Action</td>
<td>Выполнение Action по результатам выполнения FetchXML.</td>
</tr>
<tr>
<td>:new: <a href="https://github.com/ZooY/Dynamics365.Tools/wiki/FetchXML-Tools#execute-workflow">Execute Workflow</a></td>
<td>Запуск Workflow по результатам выполнения FetchXML.</td>
</tr>
<tr>
<td>:new: <a href="https://github.com/ZooY/Dynamics365.Tools/wiki/FetchXML-Tools#find-task">Find Task</a></td>
<td>Поиск Задачи с помощью FetchXML-запроса.</td>
</tr>
<tr>
<td><a href="https://github.com/ZooY/Dynamics365.Tools/wiki/FetchXML-Tools#median">Median</a></td>
<td>Вычисление медианы ряда числовых значений, возвращаемых запросом FetchXML.</td>
</tr>
Expand Down Expand Up @@ -413,7 +433,7 @@ Workflow
<td>Замена подстроки в строке.</td>
</tr><tr>
<td><a href="https://github.com/ZooY/Dynamics365.Tools/wiki/String-Tools#strings">Strings</a></td>
<td>Специальные строки (GUID).</td>
<td>Специальные строки (Случайный GUID).</td>
</tr><tr>
<td><a href="https://github.com/ZooY/Dynamics365.Tools/wiki/String-Tools#substring">Substring</a></td>
<td>Получение подстроки.</td>
Expand Down
2 changes: 2 additions & 0 deletions Source/Tools/Entity/Entity/Entity.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
<Compile Include="Workflow\GuidToAccount.cs" />
<Compile Include="Workflow\GuidToEmail.cs" />
<Compile Include="Workflow\GuidToFax.cs" />
<Compile Include="Workflow\GuidToIncident.cs" />
<Compile Include="Workflow\GuidToLetter.cs" />
<Compile Include="Workflow\GuidToPhoneCall.cs" />
<Compile Include="Workflow\GuidToBusinessUnit.cs" />
Expand All @@ -113,6 +114,7 @@
<Compile Include="Workflow\GuidToQuote.cs" />
<Compile Include="Workflow\GuidToTask.cs" />
<Compile Include="Workflow\GuidToTeam.cs" />
<Compile Include="Workflow\GuidToTheme.cs" />
<Compile Include="Workflow\GuidToUser.cs" />
<Compile Include="Workflow\GuidToWorkflow.cs" />
<Compile Include="Workflow\ParseEntityDynamicUrl.cs" />
Expand Down
4 changes: 2 additions & 2 deletions Source/Tools/Entity/Entity/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("8.0.3.2")]
[assembly: AssemblyFileVersion("8.0.3.2")]
[assembly: AssemblyVersion("8.0.3.4")]
[assembly: AssemblyFileVersion("8.0.3.4")]
27 changes: 27 additions & 0 deletions Source/Tools/Entity/Entity/Workflow/GuidToIncident.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;
using PZone.Xrm.Workflow;


namespace PZone.EntityTools.Workflow
{
/// <summary>
/// Действие возвращает сущность "Обращение" (incident) для указанного GUID.
/// </summary>
public class GuidToIncident : GuidToEntity
{
/// <summary>
/// Обращение.
/// </summary>
[Output("Incident")]
[ReferenceTarget("incident")]
public OutArgument<EntityReference> Incident { get; set; }


protected override void Execute(Context context)
{
SetValue(context, Incident, "incident");
}
}
}
27 changes: 27 additions & 0 deletions Source/Tools/Entity/Entity/Workflow/GuidToTheme.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;
using PZone.Xrm.Workflow;


namespace PZone.EntityTools.Workflow
{
/// <summary>
/// Действие возвращает сущность "Тема" (theme) для указанного GUID.
/// </summary>
public class GuidToTheme : GuidToEntity
{
/// <summary>
/// Тема.
/// </summary>
[Output("Theme")]
[ReferenceTarget("theme")]
public OutArgument<EntityReference> Theme { get; set; }


protected override void Execute(Context context)
{
SetValue(context, Theme, "theme");
}
}
}
4 changes: 3 additions & 1 deletion Source/Tools/FetchXML/FetchXML/FetchXML.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@
<Compile Include="Workflow\Average.cs" />
<Compile Include="Workflow\Concat.cs" />
<Compile Include="Workflow\Delete.cs" />
<Compile Include="Workflow\ExecuteWorkflowFromFetch.cs" />
<Compile Include="Workflow\ExecuteAction.cs" />
<Compile Include="Workflow\ExecuteWorkflow.cs" />
<Compile Include="Workflow\Count.cs" />
<Compile Include="Workflow\FindTask.cs" />
<Compile Include="Workflow\Median.cs" />
<Compile Include="Workflow\Sum.cs" />
<Compile Include="Workflow\EntityAsJson.cs" />
Expand Down
4 changes: 2 additions & 2 deletions Source/Tools/FetchXML/FetchXML/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("8.0.3.3")]
[assembly: AssemblyFileVersion("8.0.3.3")]
[assembly: AssemblyVersion("8.0.3.4")]
[assembly: AssemblyFileVersion("8.0.3.4")]
176 changes: 176 additions & 0 deletions Source/Tools/FetchXML/FetchXML/Workflow/ExecuteAction.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
using System;
using System.Activities;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Workflow;
using Newtonsoft.Json.Linq;
using PZone.Xrm.Workflow;


namespace PZone.FetchXmlTools.Workflow
{
/// <summary>
/// Запуск Action по результатам выполнения FetchXML.
/// </summary>
public class ExecuteAction : WorkflowBase
{
private string _actionName = null;
private Dictionary<string, Type> _actionProperties = null;

private Dictionary<string, Type> _crmTypes = new Dictionary<string, Type> {
{ "EntityCollection", typeof(EntityCollection) },
{ "EntityReference", typeof(EntityReference)},
{ "OptionSetValue", typeof(OptionSetValue)},
{ "String", typeof(string)},
{ "DateTime", typeof(DateTime)},
{ "Money", typeof(Money)},
{ "Decimal", typeof(decimal)},
{ "Boolean", typeof(bool)},
{ "Double", typeof(double)},
{ "Entity", typeof(Entity)},
{ "Int32", typeof(int)}
};


/// <summary>
/// Запрос FetchXML, получающий список записей.
/// </summary>
[RequiredArgument]
[Input("FetchXML Query")]
public InArgument<string> FetchXml { get; set; }


/// <summary>
/// Workflow
/// </summary>
[RequiredArgument]
[Input("Action")]
[ReferenceTarget("workflow")]
public InArgument<EntityReference> Action { get; set; }


/// <summary>
/// JSON с параметрами.
/// </summary>
[Input("JSON with Parameters")]
public InArgument<string> Parameters { get; set; }


/// <inheritdoc />
protected override void Execute(Context context)
{
var fetchXmlStr = FetchXml.Get(context);
var actionRef = Action.Get(context);
var parametersJsonStr = Parameters.Get(context);

// Получение имени и параметров действия.
if (string.IsNullOrEmpty(_actionName))
RetrieveActionProperties(context.SystemService, actionRef, out _actionName, out _actionProperties);

// Формирвоание параметров действия.
var parameters = new Dictionary<string, object>();
foreach (var property in JObject.Parse(parametersJsonStr).Properties())
parameters.Add(property.Name, property.ToObject(_actionProperties[property.Name]));

var moreRecords = false;
int page = 1;
string query = fetchXmlStr;
do
{
// Получение списка сущностей.
var collection = context.SystemService.RetrieveMultiple(new FetchExpression(query));
if (collection.Entities.Count < 1)
break;

// Формирование запросов для вызова действий.
var requests = new ExecuteMultipleRequest()
{
Settings = new ExecuteMultipleSettings()
{
ContinueOnError = false,
ReturnResponses = true
},
Requests = new OrganizationRequestCollection() { }
};
foreach (var entity in collection.Entities)
{
var request = new OrganizationRequest(_actionName)
{
["Target"] = entity.ToEntityReference()
};
request.Parameters.AddRange(parameters);
requests.Requests.Add(request);
}

// Выполнение действий.
var response = (ExecuteMultipleResponse)context.Service.Execute(requests);
if (response.IsFaulted)
{
var faultResponse = response.Responses.FirstOrDefault(r => r.Fault != null);
var faultWorkflowRequest = (ExecuteWorkflowRequest)requests.Requests[faultResponse.RequestIndex];
SetError(context, $"A record of the \"{collection.EntityName}\" type with the ID \"{faultWorkflowRequest.EntityId}\" returned an error during execution of the action {(string.IsNullOrEmpty(actionRef.Name) ? "" : $"\"{actionRef.Name}\" ")}with the ID \"{actionRef.Id}\".");
return;
}

// Организация чтения следующей страницы.
moreRecords = collection.MoreRecords;
if (moreRecords)
{
page++;
var fetchXml = XDocument.Parse(fetchXmlStr);
fetchXml.Root.SetAttributeValue("paging-cookie", System.Security.SecurityElement.Escape(collection.PagingCookie));
fetchXml.Root.SetAttributeValue("page", page);
query = fetchXml.ToString();
}
} while (moreRecords);
}


private void RetrieveActionProperties(IOrganizationService service, EntityReference actionRef, out string actionLogicalName, out Dictionary<string, Type> properties)
{
// Получаем название действия.
var action = service.Retrieve(actionRef.LogicalName, actionRef.Id, new ColumnSet("solutionid", "uniquename", "xaml"));
var solutionId = action.GetAttributeValue<Guid>("solutionid");
var query = $@"
<fetch top='1' no-lock='true'>
<entity name='solution'>
<filter>
<condition attribute='solutionid' operator='eq' value='{solutionId}'/>
</filter>
<link-entity name='publisher' from='publisherid' to='publisherid' alias='publisher'>
<attribute name='customizationprefix' />
</link-entity>
</entity>
</fetch>";
var solution = service.RetrieveMultiple(new FetchExpression(query)).Entities.FirstOrDefault();
var prefix = solution.GetAttributeValue<AliasedValue>("publisher.customizationprefix").Value.ToString();
actionLogicalName = prefix + "_" + action.GetAttributeValue<string>("uniquename");

// Получаем список входных параметров действия.
var xaml = action.GetAttributeValue<string>("xaml");
var xDoc = XDocument.Parse(xaml);
var xProperties = xDoc.Root.Elements()
.FirstOrDefault(e => e.Name.LocalName == "Members").Elements()
.Where(e => e.Name.LocalName == "Property");
properties = new Dictionary<string, Type>();
foreach (var xProperty in xProperties)
{
var name = xProperty.Attribute("Name").Value;
var typeStr = xProperty.Attribute("Type").Value;
if (name == "InputEntities" || name == "CreatedEntities" || !typeStr.StartsWith("InArgument"))
continue;
typeStr = Regex.Match(typeStr, "InArgument[(](?<type>.+)[)]").Groups["type"].Value;
var typeParts = typeStr.Split(new char[] { ':' }, 2);
typeStr = typeParts.Length == 1 ? typeStr : typeParts[1];
var type = _crmTypes[typeStr];
properties.Add(name, type);
}
}
}
}
Loading

0 comments on commit d9a1f07

Please sign in to comment.