Я следую статье это, чтобы изменить этап потока бизнес-процессов в подключаемом модуле C#. Я могу переместить этап на следующий этап, но я получаю сообщение об ошибке, когда пытаюсь вернуться к предыдущему этапу. Ошибка ниже - это то, что я получаю в пользовательском интерфейсе от Dynamics. Когда я отлаживаю плагин, я получаю исключение FaultException<OrganizationServiceFault>, которое не содержит никакой информации. Почему я получаю сообщение об ошибке и как я могу изменить свой код, чтобы успешно вернуться к предыдущему этапу в моем потоке бизнес-процессов?
Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: An unexpected error occurred.
Detail: <OrganizationServiceFault xmlns = "http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:i = "http://www.w3.org/2001/XMLSchema-instance">
<ActivityId>5df51362-b7c1-4817-a8d0-de2d63b15c17</ActivityId>
<ErrorCode>-2147220970</ErrorCode>
<ErrorDetails xmlns:a = "http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<Message>An unexpected error occurred.</Message>
<Timestamp>2018-07-19T18:55:42.6625925Z</Timestamp>
<ExceptionSource i:nil = "true" />
<InnerFault>
<ActivityId>5df51362-b7c1-4817-a8d0-de2d63b15c17</ActivityId>
<ErrorCode>-2147220970</ErrorCode>
<ErrorDetails xmlns:a = "http://schemas.datacontract.org/2004/07/System.Collections.Generic" />
<Message>System.NullReferenceException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #0D309052</Message>
<Timestamp>2018-07-19T18:55:42.6625925Z</Timestamp>
<ExceptionSource i:nil = "true" />
<InnerFault i:nil = "true" />
<OriginalException i:nil = "true" />
<TraceText i:nil = "true" />
</InnerFault>
<OriginalException i:nil = "true" />
<TraceText i:nil = "true" />
</OrganizationServiceFault>
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;
Client client = (Client)service.Retrieve(
Client.LogicalName,
new Guid("75FE165F-848B-E811-80F3-005056B33317"),
new ColumnSet(new String[]{
Client.Properties.ClientId
})
);
client.ChangeStage(service);
public void ChangeStage(IOrganizationService service)
{
// Get Process Instances
RetrieveProcessInstancesRequest processInstanceRequest = new RetrieveProcessInstancesRequest
{
EntityId = this.Id,
EntityLogicalName = this.LogicalName
};
RetrieveProcessInstancesResponse processInstanceResponse = (RetrieveProcessInstancesResponse)service.Execute(processInstanceRequest);
// Declare variables to store values returned in response
int processCount = processInstanceResponse.Processes.Entities.Count;
Entity activeProcessInstance = processInstanceResponse.Processes.Entities[0]; // First record is the active process instance
Guid activeProcessInstanceID = activeProcessInstance.Id; // Id of the active process instance, which will be used later to retrieve the active path of the process instance
// Retrieve the active stage ID of in the active process instance
Guid activeStageID = new Guid(activeProcessInstance.Attributes["processstageid"].ToString());
// Retrieve the process stages in the active path of the current process instance
RetrieveActivePathRequest pathReq = new RetrieveActivePathRequest
{
ProcessInstanceId = activeProcessInstanceID
};
RetrieveActivePathResponse pathResp = (RetrieveActivePathResponse)service.Execute(pathReq);
string activeStageName = "";
int activeStagePosition = -1;
Console.WriteLine("\nRetrieved stages in the active path of the process instance:");
for (int i = 0; i < pathResp.ProcessStages.Entities.Count; i++)
{
// Retrieve the active stage name and active stage position based on the activeStageId for the process instance
if (pathResp.ProcessStages.Entities[i].Attributes["processstageid"].ToString() == activeStageID.ToString())
{
activeStageName = pathResp.ProcessStages.Entities[i].Attributes["stagename"].ToString();
activeStagePosition = i;
}
}
// Retrieve the stage ID of the next stage that you want to set as active
activeStageID = (Guid)pathResp.ProcessStages.Entities[activeStagePosition - 1].Attributes["processstageid"];
// Retrieve the process instance record to update its active stage
ColumnSet cols1 = new ColumnSet();
cols1.AddColumn("activestageid");
Entity retrievedProcessInstance = service.Retrieve("ccseq_bpf_clientsetup", activeProcessInstanceID, cols1);
// Set the next stage as the active stage
retrievedProcessInstance["activestageid"] = new EntityReference(ProcessStage.LogicalName, activeStageID);
service.Update(retrievedProcessInstance);
}
Я нашел статью это, в которой объясняется, как обновить Stage с помощью веб-API. Когда я пробую этот метод, я получаю сообщение об ошибке:
An undeclared property 'activestageid' which only has property annotations in the payload but no property value was found in the payload. In OData, only declared navigation properties and declared named streams can be represented as properties without values.
Я безуспешно пробовал несколько разновидностей activestageid (ActiveStageId, _activestageid_value).
Основываясь на отзывах Аруна, я безуспешно попробовал следующие вызовы веб-API. Идентификатор в скобках в URL-адресе (ccseq_bpf_clientsetups (###)) я извлек из BusinessProcessFlowInstanceId в таблице ccseq_bpf_clientsetups. Идентификатор этапов процесса, который я извлек из ProcessStageId в таблице ProcessStageBase.
// Attempt 1
PATCH /COHEN/api/data/v8.2/ccseq_bpf_clientsetups(bc892aec-2594-e811-80f4-005056b33317) HTTP/1.1
{ "[email protected]": "/processstages(70018854-db7c-4612-915b-2ad7870a8574)"}
// Attempt 2
PATCH /COHEN/api/data/v8.2/ccseq_bpf_clientsetups(bc892aec-2594-e811-80f4-005056b33317) HTTP/1.1
{ "[email protected]": "/processstages(70018854-db7c-4612-915b-2ad7870a8574)"}
// Attempt 3
PATCH /COHEN/api/data/v8.2/ccseq_bpf_clientsetups(bc892aec-2594-e811-80f4-005056b33317) HTTP/1.1
{ "[email protected]": "/processstages(70018854-db7c-4612-915b-2ad7870a8574)"}
Я загрузил CRM Rest Builder от jLattimer и попытался запустить JavaScript, созданный его инструментом. Код был идентичен тому, что я написал ранее, и, к сожалению, не работал. На данный момент я вполне уверен, что изменение этапов не поддерживается в версии 8.2 веб-API.
@jasonscript Нет, на текущем этапе нет обязательных полей. Мы пробовали отступить в законченном БПФ, а также на незавершенном БПФ. В обоих случаях на текущем этапе не было обязательных полей. В случае неполного BPF на предыдущем этапе было обязательное поле, к которому мы пытались вернуться, но оно имеет указанное значение





У меня есть код, который пытается переместить этап потока бизнес-процесса вперед в качестве настраиваемого этапа рабочего процесса (а не плагина). Я разместил это ниже.
Разница, которую я вижу:
active path, я просто получаю все доступные этапы процессаTraversedPathКод:
var activeInstancesRequest = new RetrieveProcessInstancesRequest
{
EntityId = TargetEntity.Id,
EntityLogicalName = TargetEntity.LogicalName
};
var activeInstancesResponse = (RetrieveProcessInstancesResponse)base.OrgService.Execute(activeInstancesRequest);
var process = activeInstancesResponse.Processes.Entities.Select(x => x.ToEntity<BusinessProcessFlowInstance>()).ToList();
var stages = base.XrmContext.ProcessStageSet
.Where(s => s.ProcessId.Id == process.FirstOrDefault().ProcessId.Id)
.Select(s => new ProcessStage
{
ProcessStageId = s.ProcessStageId,
StageName = s.StageName
})
.ToList();
var targetStage = stages.Where(stage => stage.StageName == targetStageName).FirstOrDefault();
if (targetStage != null)
{
crmWorkflowContext.Trace($"BPF contains target stage (\"{targetStageName}\"). Attempting to update BPF");
// Setting the Traversed Path is necessary for the Business Process Flow to show the active Stage
// If this is not updated then although the new Stage is set as current, the previous Stage remains actively selected
var traversedPath = $"{bpf.TraversedPath},{targetStage.ProcessStageId.Value}";
var update = new BusinessProcessFlowInstance()
{
BusinessProcessFlowInstanceId = bpf.BusinessProcessFlowInstanceId,
ProcessStageId = targetStage.ProcessStageId,
TraversedPath = traversedPath
};
xrmContext.Attach(update);
xrmContext.UpdateObject(update);
}
Я тестировал быстро, я мог двигаться вперед / назад в Lead to Opportunity Sales Process в онлайн-организации vanilla v9.
Я просто успешно протестировал запрос Web API PATCH от CRM REST builder.
Разработать, чтобы предложить (вперед)
var entity = {};
entity["[email protected]"] = "/processstages(3A275C22-FC45-4E89-97FC-41E5EC578743)";
var req = new XMLHttpRequest();
req.open("PATCH", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/leadtoopportunitysalesprocesses(1674DB10-1994-E811-A969-000D3A1A9FA9)", true);
Предлагаю разработать (назад)
var entity = {};
entity["[email protected]"] = "/processstages(BFC9108C-8389-406B-9166-2C3298A2E41F)";
var req = new XMLHttpRequest();
req.open("PATCH", Xrm.Page.context.getClientUrl() + "/api/data/v8.2/leadtoopportunitysalesprocesses(1674DB10-1994-E811-A969-000D3A1A9FA9)", true);
Это не что иное, как отмеченное ниже как необходимое.
Не требуется
1574DB10-1994-E811-A969-000D3A1A9FA9 - leadid
919E14D1-6489-4852-ABD0-A63A6ECAAC5D - processid
f99b4d48-7aad-456e-864a-8e7d543f7495, bfc9108c-8389-406b-9166-2c3298a2e41f - traversedpath
Нужный
1674DB10-1994-E811-A969-000D3A1A9FA9 - businessprocessflowinstanceid
BFC9108C-8389-406B-9166-2C3298A2E41F - activestageidразвивать
3A275C22-FC45-4E89-97FC-41E5EC578743 - activestageidпредлагать
Обновлять:
Я также успешно протестировал приведенный ниже фрагмент в версии 8 [Версия 1612 (8.2.2.2160) (БД 8.2.2.2160) онлайн]
Фактически он двигался вперед / назад безtraversedpath.
var entity = {};
entity["[email protected]"] = "/processstages(BFC9108C-8389-406B-9166-2C3298A2E41F)";
entity.traversedpath = "f99b4d48-7aad-456e-864a-8e7d543f7495,bfc9108c-8389-406b-9166-2c3298a2e41f";
var req = new XMLHttpRequest();
req.open("PATCH", Xrm.Page.context.getClientUrl() + "/api/data/v8.0/leadtoopportunitysalesprocesses(E5B70E69-2094-E811-8145-C4346BDCF2F1)", true);
Но получил ошибку Bad request со следующим:
entity.activestageid = {
Id: "3A275C22-FC45-4E89-97FC-41E5EC578743",
LogicalName: "processstage"
};
В настоящее время я использую v8, что может быть частью проблемы. Кроме того, в соответствии с документацией потребуется traversedpath, поэтому отсутствие его включения заставит меня немного нервничать
@TimHutchison Я проверил, что пройденный путь быстро вычисляется как в прямом, так и в обратном направлении. Я также помню, что делал это в v8 вручную ..
@TimHutchison Я попробовал тот же запрос (+ пройденный путь) от построителя CRM Rest в одной из резервных организаций v8, получаю ошибку неверного запроса. :(
Я обновил свой ответ своей попыткой вашего решения. Есть дополнительные мысли?
@TimHutchison забудьте про свой BPF, даже изменение OOB BPF не работает. :) пробовал? этот бесполезный Плохой запрос продолжает поступать ..
Я не совсем понимаю, что ты говоришь, Арун. Что вы имеете в виду, говоря «забудьте про свой BPF, даже если изменение OOB BPF не работает»?
@TimHutchison Я получил ошибку в версии 8 для OOB Lead BPF. Неважно, умеет разбираться. см. обновление в ответе, и вы также можете быстро протестировать в своей организации, импортировав конструктор CRM Rest. Это поможет идентифицировать проблему с окружающей средой, логической проблемой и ошибкой версии продукта OOB.
@TimHutchison. У вас была возможность проверить код с другим OOB BPF в вашей среде?
Я не смог вернуться к этой части головоломки, поскольку у нас не хватает времени, и другие вещи стали более приоритетными. Я назначил награду в знак признательности за вашу помощь в этом вопросе и потому, что ожидаю, что этот ответ в конечном итоге приведет меня к решению. Спасибо!
@TimHutchison, спасибо, извините за это, на самом деле я хотел решить эту проблему, указав / угловую основную причину в вашем сценарии BPF или версии среды, тогда мы бы продолжили исправление ошибки продукта или обходной путь ..
У меня была такая же проблема. Это намного проще, чем вы думаете. ОК, откройте расширенный поиск и выберите {ваш BPF}. Добавьте два столбца в запрос: {ваш объект} {пройденный путь}.
Хорошо, поэтому посмотрите на пройденный путь для объекта, который фактически находится на предыдущем этапе (тот, к которому вы хотите вернуться).
С помощью вашего кода вам нужно динамически разбить пройденный путь (.Split (',')) или что-то подобное ... удалить последний этап (тот, в котором вы сейчас находитесь), и вуаля! Вы готовите на бензине.
если текущий пройденный путь был массивом:
string[] currentPath = {"A", "B", "C", "D"};
ваш предыдущий путь должен быть:
string[] previousPath = {"A", "B", "C"};
Вот как вы могли бы сделать это в коде, предполагая, что «entity» - это ваша извлеченная сущность:
string traversedPath = (string) entity["traversedpath"];
string[] stages = traversedPath.Split(',');
string newPath = "";
//use length - 1 to omit last stage (your current stage)
for (int i = 0; i < stages.Length - 1; i++)
{
if (i != stages.Length - 1)
newPath += stages[i] + ",";
else
newPath += stages[i];
}
entity["processid"] = new Guid("BPF Guid") //may be optional
entity["stageid"] = new Guid("previous stage guid");
entity["traversedpath"] = newPath;
service.Update(entity);
По сути, пройденный путь не + = 'ваш предыдущий этап' до конца пройденного пути. Он хочет установить пройденный путь на ОРИГИНАЛЬНЫЙ пройденный путь для «вашего предыдущего этапа». Узнайте, какой пройденный путь соответствует желаемой стадии, и либо жестко запрограммируйте эту присоску в строку (если она только собирается перейти на эту стадию, когда-либо) .. или сделайте это программно с помощью метода .Split (',') на Атрибут Entity ["traversedpath"] в коде.
Помните, вы вычитаете, а не добавляете к пройденному пути. Мне потребовалось много недействительных ошибок пройденного пути, чтобы прийти к такому выводу ... и это работает. Удачи!
Есть ли обязательные поля на текущем этапе? Это может помешать вам покинуть активную стадию.