Cambio de la Etapa de flujo del proceso de negocios en C # Plugin

Estoy siguiendo este artículo para cambiar mi etapa de flujo de procesos de negocios dentro del complemento ac #. Puedo pasar de la etapa a la siguiente etapa, pero recibo un error cuando bash volver a la etapa anterior. El error a continuación es lo que recibo en la interfaz de usuario de Dynamics. Cuando depuro el complemento, recibo una FaultException que no contiene ninguna información. ¿Por qué recibo un error y cómo puedo modificar mi código para volver exitosamente a una etapa anterior en mi flujo de procesos de negocios?

Error

 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:  5df51362-b7c1-4817-a8d0-de2d63b15c17 -2147220970  An unexpected error occurred. 2018-07-19T18:55:42.6625925Z   5df51362-b7c1-4817-a8d0-de2d63b15c17 -2147220970  System.NullReferenceException: Microsoft Dynamics CRM has experienced an error. Reference number for administrators or support: #0D309052 2018-07-19T18:55:42.6625925Z         

Enchufar

 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); 

Cambiar etapa

 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); } 

Actualizar

Encontré este artículo que explica cómo actualizar el escenario utilizando la API web. Cuando bash este método, me sale el error:

Una propiedad no declarada ‘activestageid’ que solo tiene anotaciones de propiedad en la carga útil, pero no se encontró ningún valor de propiedad en la carga útil. En OData, solo las propiedades de navegación declaradas y las secuencias con nombre declaradas se pueden representar como propiedades sin valores.

He probado algunas variedades de ‘activestageid’ sin éxito (ActiveStageId, _activestageid_value).


Actualización 2

Basándome en los comentarios de Arun, probé las siguientes llamadas a la API web sin éxito. La ID dentro de los corchetes en la url (ccseq_bpf_clientsetups (###)) la saqué de BusinessProcessFlowInstanceId en la tabla ccseq_bpf_clientsetups. El ID de las etapas de proceso que obtuve de ProcessStageId en la tabla ProcessStageBase

 // Attempt 1 PATCH /COHEN/api/data/v8.2/ccseq_bpf_clientsetups(bc892aec-2594-e811-80f4-005056b33317) HTTP/1.1 { "ActiveStageID@odata.bind": "/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 { "activestageid@odata.bind": "/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 { "ActiveStageId@odata.bind": "/processstages(70018854-db7c-4612-915b-2ad7870a8574)"} 

Actualización 3

Descargué CRM Rest Builder de jLattimer e intenté ejecutar el JavaScript generado por su herramienta. El código era idéntico a lo que había escrito anteriormente y, lamentablemente, no funcionó. En este punto, estoy bastante seguro de que las etapas cambiantes no se admiten en v8.2 de la API web.

Tengo algunos códigos que intentan avanzar en la etapa de flujo de procesos de negocios, como un paso de flujo de trabajo personalizado (en lugar de un complemento). Lo he publicado a continuación.

La diferencia que veo son:

  • Me estoy moviendo hacia adelante (no hacia atrás)
  • Probablemente no estoy siguiendo las mejores prácticas 🙂
  • No estoy recuperando la active path , solo obtengo todas las etapas disponibles para el proceso
  • También estoy configurando la propiedad TraversedPath

Código:

 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()).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); } 

Probé rápidamente, fui capaz de avanzar / retroceder dentro del Lead to Opportunity Sales Process en vanilla v9 online org.

Simplemente probé con éxito la solicitud de PATCH API web del generador de REST de CRM.

Desarrollar para Proponer (adelante)

 var entity = {}; entity["activestageid@odata.bind"] = "/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); 

Proponer para Desarrollar (hacia atrás)

 var entity = {}; entity["activestageid@odata.bind"] = "/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); 

No hay nada más que marcado como se necesita a continuación.

Innecesario
1574DB10-1994-E811-A969-000D3A1A9FA9 – leadid
919E14D1-6489-4852-ABD0-A63A6ECAAC5D – processid
f99b4d48-7aad-456e-864a-8e7d543f7495, bfc9108c-8389-406b-9166-2c3298a2e41f – traversedpath

Necesario
1674DB10-1994-E811-A969-000D3A1A9FA9 – businessprocessflowinstanceid
BFC9108C-8389-406B-9166-2C3298A2E41F – desarrollo de activestageid
3A275C22-FC45-4E89-97FC-41E5EC578743 – propuesta de activestageid


Actualizar:

También he probado el fragmento de código siguiente con éxito en v8 [ Versión 1612 (8.2.2.2160) (DB 8.2.2.2160) en línea ]

De hecho, se estaba moviendo hacia atrás / adelante sin traversedpath .

 var entity = {}; entity["activestageid@odata.bind"] = "/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); 

Pero tiene error de Bad request incorrecta con a continuación:

 entity.activestageid = { Id: "3A275C22-FC45-4E89-97FC-41E5EC578743", LogicalName: "processstage" }; 

Yo estaba teniendo el mismo problema. Es mucho más simple de lo que piensas. OK, abra búsqueda avanzada, seleccione {su BPF}. Agregue dos columnas para consultar: {su Entidad} {ruta atravesada}.

De acuerdo, mire la ruta atravesada para una entidad que se encuentra realmente en la etapa anterior (a la que desea volver).

Con su código, necesita dividir dinámicamente la ruta atravesada (.Split (‘,’)) o algo similar … elimine la última etapa (en la que se encuentra actualmente), ¡y listo! Estás cocinando con gasolina.

si la ruta atravesada actual fuera una matriz:

 string[] currentPath = {"A", "B", "C", "D"}; 

tu camino anterior debe ser:

 string[] previousPath = {"A", "B", "C"}; 

A continuación le indicamos cómo podría hacerlo en código, asumiendo que ‘entidad’ es su entidad recuperada:

 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); 

Básicamente, la ruta atravesada no + = 'su etapa anterior' al final de la ruta recorrida. Quiere establecer la ruta atravesada en la ruta ORIGINAL atravesada para "su etapa anterior". Averigüe cuál es la ruta atravesada para la etapa deseada y codifique la secuencia de código (si es que va a ir a esa etapa) ... o hágalo mediante progtwigción a través del método .Split (',') en el Entidad ["traversedpath"] atributo en el código.

Recuerde, está restando de, no agregando a ... la ruta atravesada. Me tomó muchos errores de ruta atravesados ​​inválidos para llegar a esta conclusión ... y funciona. ¡Buena suerte!