Guía Definitiva de Activity Parties en Dynamics 365

10/09/2019

Valoración: 3.99 (15697 votos)

Si alguna vez has trabajado con el desarrollo en Microsoft Dynamics 365 o Power Apps, es casi seguro que te has enfrentado al reto de manipular las actividades. Tareas como llamadas de teléfono, correos electrónicos o citas son el pan de cada día, pero programáticamente pueden presentar desafíos únicos. Uno de los conceptos más confusos, pero a la vez más potentes, son los campos de tipo Party List (Lista de participantes). A diferencia de un campo de búsqueda normal (lookup) que apunta a un único registro, un campo Party List como el "Para" o "CC" de un correo electrónico puede contener múltiples destinatarios de diferentes tipos de entidad (Cuentas, Contactos, Usuarios, etc.). Aquí es donde entra en juego la entidad ActivityParty, el pilar fundamental que sostiene esta funcionalidad. En este artículo, desglosaremos qué es una Activity Party, cómo funciona y, lo más importante, cómo puedes leer y escribir en estos campos utilizando tanto C# en el lado del servidor como JavaScript con la Web API en el lado del cliente.

Índice de Contenido

¿Qué es una Actividad en Dynamics 365?

Antes de sumergirnos en el concepto de Activity Party, es crucial tener claro qué es una actividad. En Dynamics 365, las actividades son acciones que los usuarios realizan para interactuar con los clientes y gestionar sus procesos de negocio. Son la forma de registrar comunicaciones y tareas. Las actividades predeterminadas más comunes incluyen:

  • Correo electrónico (Email)
  • Llamada de teléfono (Phone Call)
  • Tarea (Task)
  • Cita (Appointment)
  • Carta (Letter)
  • Fax

Cada vez que se crea un registro de una de estas entidades, el sistema también crea un registro correspondiente en una tabla llamada "Activity Pointer" (puntero de actividad). Esta tabla actúa como un agregador, permitiendo ver todas las actividades de diferentes tipos en una sola vista cronológica, por ejemplo, en la escala de tiempo de un registro de Contacto o Cuenta.

Entendiendo el Concepto de Activity Party

Ahora, la pregunta clave: ¿qué es una Activity Party? Una ActivityParty (o Participante de la actividad) es una entidad especial en Dataverse que representa a una persona o grupo asociado a una actividad. Piénsalo como un registro de enlace. En lugar de que el correo electrónico tenga una conexión directa y múltiple con Contactos y Cuentas, tiene una conexión con varios registros de ActivityParty. A su vez, cada registro de ActivityParty apunta a un único Contacto, Cuenta, Usuario, etc.

Esta estructura es la que permite la magia de los campos Party List. El campo "Para" de un correo no almacena directamente los GUIDs de los destinatarios; en su lugar, almacena una colección de registros de ActivityParty. Cada uno de estos registros tiene dos atributos clave:

  1. partyid: Un campo de búsqueda que apunta al registro real (por ejemplo, al Contacto "Juan Pérez" o a la Cuenta "Empresa XYZ").
  2. participationtypemask: Un campo numérico que define el rol de ese participante en la actividad (¿es el remitente?, ¿el destinatario?, ¿un asistente opcional?).

Gracias a este diseño, un solo campo en el formulario de correo electrónico puede gestionar una lista compleja de participantes con diferentes roles y de diferentes tipos de entidad.

Tipos de Activity Party (ParticipationTypeMask)

El rol de cada participante se define mediante un código numérico en el campo ParticipationTypeMask. Conocer estos valores es esencial para poder filtrar y crear participantes de forma correcta en nuestro código. A continuación, se muestra una tabla con los tipos de participantes disponibles:

Tipo de ParticipanteValor NuméricoDescripción
Sender1Especifica el remitente de la actividad.
ToRecipient2Especifica el destinatario en el campo "Para".
CCRecipient3Especifica el destinatario en el campo "CC" (Con copia).
BccRecipient4Especifica el destinatario en el campo "CCO" (Con copia oculta).
RequiredAttendee5Especifica un asistente requerido (ej. en una cita).
OptionalAttendee6Especifica un asistente opcional.
Organizer7Especifica el organizador de la actividad.
Regarding8Especifica el registro "Referente a" de la actividad.
Owner9Especifica el propietario de la actividad.
Resource10Especifica un recurso (ej. una sala de reuniones en una cita).
Customer11Especifica un cliente.
ChatParticipant12Especifica un participante en un chat de Teams.
Related13Especifica uno o más registros relacionados.

Disponibilidad de Tipos de Party por Actividad

No todos los tipos de participantes están disponibles para todas las actividades. Por ejemplo, no tiene sentido tener un "Asistente Requerido" en una llamada de teléfono. La siguiente tabla detalla qué tipos de participantes son compatibles con las actividades más comunes:

Entidad de ActividadTipos de Participante SoportadosAtributo Correspondiente
Appointment (Cita)OptionalAttendee, Organizer, RequiredAttendeeoptionalattendees, organizer, requiredattendees
Email (Correo electrónico)BccRecipient, CcRecipient, Sender, ToRecipient, Relatedbcc, cc, from, to, related
FaxSender, ToRecipientfrom, to
Letter (Carta)BccRecipient, Sender, ToRecipientbcc, from, to
PhoneCall (Llamada)Sender, ToRecipientfrom, to
ServiceAppointment (Cita de Servicio)Customer, Resourcecustomers, resources

Manipulación de Activity Parties con Código

Ahora que la teoría está clara, pasemos a la práctica. Veremos cómo interactuar con estos campos tanto desde C# (para plugins, workflows o aplicaciones de consola) como desde JavaScript (para personalizaciones en el formulario).

1. Gestión con C# (Lado del Servidor)

En C#, la clave es crear instancias de la entidad activityparty y luego asignarlas como un array al campo Party List correspondiente (from, to, etc.) de la entidad de actividad principal.

Establecer un Único Destinatario en un Correo

Este es el escenario más simple. Queremos crear un correo electrónico con un remitente (un usuario del sistema) y un destinatario (una cuenta).

// service es tu objeto IOrganizationService // 1. Declarar las entidades de tipo activityparty Entity fromParty = new Entity("activityparty"); Entity toParty = new Entity("activityparty"); // 2. Asignar el participante real usando EntityReference en el campo "partyid" // El remitente será un usuario del sistema fromParty["partyid"] = new EntityReference("systemuser", new Guid("D72D8D9E-FCEC-4C6B-8340-A2CB9FAA88D5")); // El destinatario será una cuenta toParty["partyid"] = new EntityReference("account", new Guid("475B158C-541C-E511-80D3-3863BB347BA8")); // 3. Crear la entidad de correo electrónico Entity email = new Entity("email"); // 4. Asignar los activityparty a los campos "from" y "to". // ¡Importante! Estos campos esperan un array de entidades. email["from"] = new Entity[] { fromParty }; email["to"] = new Entity[] { toParty }; // 5. Establecer otros atributos como el asunto, cuerpo y el registro "Referente a" email["subject"] = "Correo creado desde código para un solo destinatario"; email["description"] = "Este es el cuerpo del correo."; EntityReference regardingObject = new EntityReference("contact", new Guid("49A0E5B9-88DF-E311-B8E5-6C3BE5A8B200")); email["regardingobjectid"] = regardingObject; // 6. Crear el registro de correo Guid emailId = service.Create(email); Console.WriteLine("Correo creado con éxito."); 

Establecer Múltiples Destinatarios en un Correo

El proceso es muy similar, pero en lugar de asignar un array con un solo elemento al campo "to", crearemos un array con múltiples entidades activityparty.

// service es tu objeto IOrganizationService // 1. Crear el participante para el campo "from" Entity fromParty = new Entity("activityparty"); fromParty["partyid"] = new EntityReference("systemuser", new Guid("D72D8D9E-FCEC-4C6B-8340-A2CB9FAA88D5")); // 2. Crear múltiples participantes para el campo "to" // Dos cuentas y dos contactos Entity toParty1 = new Entity("activityparty"); toParty1["partyid"] = new EntityReference("account", new Guid("475B158C-541C-E511-80D3-3863BB347BA8")); Entity toParty2 = new Entity("activityparty"); toParty2["partyid"] = new EntityReference("account", new Guid("A8A19CDD-88DF-E311-B8E5-6C3BE5A8B200")); Entity toParty3 = new Entity("activityparty"); toParty3["partyid"] = new EntityReference("contact", new Guid("25A17064-1AE7-E611-80F4-E0071B661F01")); Entity toParty4 = new Entity("activityparty"); toParty4["partyid"] = new EntityReference("contact", new Guid("49A0E5B9-88DF-E311-B8E5-6C3BE5A8B200")); // 3. Crear la entidad de correo electrónico Entity email = new Entity("email"); email["subject"] = "Correo para múltiples destinatarios"; email["description"] = "Este correo se envía a varias cuentas y contactos."; // 4. Asignar los arrays de activityparty a los campos "from" y "to" email["from"] = new Entity[] { fromParty }; email["to"] = new Entity[] { toParty1, toParty2, toParty3, toParty4 }; // 5. Crear el registro Guid emailId = service.Create(email); Console.WriteLine("Correo para múltiples destinatarios creado con éxito."); 

Obtener los Valores de un Campo Party List

Para leer los valores, recuperamos la actividad y accedemos al campo Party List, que nos devolverá una EntityCollection de registros activityparty. Luego, iteramos sobre esa colección para extraer el partyid de cada uno.

public static void ObtenerParticipantes(Guid emailId, IOrganizationService service) { // Recuperar el correo electrónico, solicitando los campos "from" y "to" Entity email = service.Retrieve("email", emailId, new ColumnSet("from", "to")); // Obtener la colección de participantes del campo "from" EntityCollection fromCollection = email.GetAttributeValue<EntityCollection>("from"); if (fromCollection != null && fromCollection.Entities.Count > 0) { Console.WriteLine("Remitentes:"); foreach (Entity activityParty in fromCollection.Entities) { EntityReference partyId = activityParty.GetAttributeValue<EntityReference>("partyid"); Console.WriteLine($" - Nombre: {partyId.Name}, Tipo: {partyId.LogicalName}"); } } // Obtener la colección de participantes del campo "to" EntityCollection toCollection = email.GetAttributeValue<EntityCollection>("to"); if (toCollection != null && toCollection.Entities.Count > 0) { Console.WriteLine("Destinatarios:"); foreach (Entity activityParty in toCollection.Entities) { EntityReference partyId = activityParty.GetAttributeValue<EntityReference>("partyid"); Console.WriteLine($" - Nombre: {partyId.Name}, Tipo: {partyId.LogicalName}"); } } } 

2. Lectura con JavaScript y Web API (Lado del Cliente)

En el lado del cliente, la situación es diferente. Si intentas leer un campo como `to` directamente desde un registro de correo electrónico usando la Web API, recibirás un error o un valor nulo. Esto se debe a que estos campos no son atributos directos, sino relaciones. La forma correcta de leerlos es consultando directamente la entidad activityparty.

La consulta debe filtrar por dos condiciones:

  1. El ID de la actividad principal (_activityid_value).
  2. El tipo de participante que queremos obtener (participationtypemask).

Ejemplo de Código para Leer el Campo "Para"

El siguiente código JavaScript asíncrono utiliza `Xrm.WebApi.retrieveMultipleRecords` para obtener todos los destinatarios del campo "Para" (cuyo `participationtypemask` es 2) de una actividad específica.

async function obtenerDestinatarios(activityId) { try { // Definimos la consulta a la entidad activityparty const fetchXml = `? $filter=_activityid_value eq ${activityId} and participationtypemask eq 2& $select=_partyid_value`; // Ejecutamos la consulta const results = await Xrm.WebApi.retrieveMultipleRecords("activityparty", fetchXml); if (results.entities.length > 0) { console.log("Destinatarios encontrados:"); // Iteramos sobre los resultados y extraemos la información de cada participante results.entities.forEach(party => { const partyId = party["_partyid_value"]; const partyName = party["[email protected]"]; const partyType = party["[email protected]"]; console.log(`ID: ${partyId}, Nombre: ${partyName}, Tipo de Entidad: ${partyType}`); }); } else { console.log("No se encontraron destinatarios en el campo 'Para'."); } } catch (error) { console.error("Error al obtener los destinatarios: ", error.message); } } // Para usarlo, simplemente llama a la función con el GUID de tu actividad (correo, cita, etc.) // Por ejemplo, desde un evento OnLoad del formulario: // const recordId = formContext.data.entity.getId().replace(/[{}]/g, ""); // obtenerDestinatarios(recordId); 

Este enfoque es robusto y es la forma recomendada por Microsoft para interactuar con estos campos desde el cliente. Te permite obtener no solo el nombre y el ID, sino también el tipo lógico de la entidad de cada participante, algo crucial si necesitas aplicar lógica diferente para Cuentas, Contactos o Usuarios.

Preguntas Frecuentes (FAQ)

¿Por qué no puedo ver los campos "Para" o "De" directamente en la Web API de la entidad de correo electrónico?
Porque no son campos simples, sino campos Party List. Su valor no está almacenado en la tabla de correo electrónico, sino que se representa a través de registros relacionados en la tabla ActivityParty. Debes consultar esta última tabla para obtener los participantes.
¿Puedo agregar un tipo de entidad personalizado a un campo Party List?
No de forma predeterminada. Los campos Party List están diseñados para funcionar con un conjunto específico de entidades habilitadas para actividades (como Cuenta, Contacto, Prospecto, Usuario, Cola, etc.). No es posible añadir entidades personalizadas a estos campos sin soluciones no soportadas.
¿Cuál es la diferencia entre `Regarding` (Referente a) y un `ActivityParty`?
El campo `Regarding` (regardingobjectid) establece el contexto principal de la actividad; es decir, sobre qué trata la actividad (por ejemplo, una llamada referente a una Oportunidad). Los `ActivityParty` definen quiénes están involucrados en esa actividad (quién llamó, a quién se llamó, etc.). Curiosamente, el propio registro `Regarding` también se almacena como un tipo de ActivityParty con participationtypemask igual a 8.

Conclusión

Las Activity Parties y los campos Party List son una de las características más poderosas y, a veces, complejas de Dynamics 365. Aunque su estructura indirecta puede parecer intimidante al principio, entender que todo se gestiona a través de la entidad intermediaria ActivityParty es la clave para desbloquear su potencial. Ya sea que estés escribiendo un plugin en C# para automatizar la creación de correos electrónicos o desarrollando un script en JavaScript para validar destinatarios en un formulario, dominar la creación y lectura de registros activityparty te convertirá en un desarrollador mucho más eficaz en el ecosistema de Power Platform.

Si quieres conocer otros artículos parecidos a Guía Definitiva de Activity Parties en Dynamics 365 puedes visitar la categoría Juegos.

Subir