Cómo integrar Bizagi con Salesforce

<< Clic para mostrar Tabla de Contenidos >>

Navegación:  Bizagi Studio > ¿Cómo hacer? .... > Temas de integración >

Cómo integrar Bizagi con Salesforce

Introducción

La integración de Bizagi con un CRM como Salesforce, es soportada a través de más de una alternativa.

Esta sección presenta un ejemplo de cómo presentar en Bizagi todos los prospectos (leads) almacenados en Salesforce, mientras permite al mismo usuario crear un nuevo prospecto basado en la información ya ingresada en Bizagi:

 

Sforce_Execute1

 

Alternativas

Para algunos escenarios donde quiera que Bizagi se conecte a sus sistemas corporativos de CRM, ya sea para traer información (i.e., Prospectos, Cuentas, Oportunidades o Contactos) o para crear nuevos registros, usted cuenta con estas funcionalidades:

 

1. Conector de servicios Web de Bizagi

Le permite conectarse a servicios Web compatibles con SOAP sin necesidad de programar.

Para más información sobre el conector de servicios Web, consulte Invocar servicios externos desde Bizagi.

 

2. Librería de componentes de Bizagi

Le permite crear su propios componentes codificados y empaquetarlos en Bizagi, de tal forma que puede extender sus reglas de negocio usando dichos componentes directamente

Para más información sobre la funcionalidad de la Librería de Componentes de Bizagi, consulte Integrar APIs o código personalizado en Bizagi.

 

note_pin

Aunque la opción preferida es usualmente el conector de servicios Web, para este artículo que involucra servicios de Salesforce, esta alternativa no es optima.

Más adelante se describe cuándo es mejor usar cada una.

 

API de Salesforce

Como Salesforce se ofrece como un servicio en la nube el cual tiene un API que puede ser accedido por Internet, se requiere el uso de un ID de sesión dinámica para invocar todos sus métodos (por razones de seguridad en la nube, para restringir invocaciones de sus servicios en una franja de tiempo en la cuál dicho ID de sesión es válido).

El API de Salesforce basado en SOA utiliza un endpoint de autenticación que está separado del endpoint de servicio, lo cual implica que la lógica detrás sigue un flujo similar al usado por aquellos basados en OAuth exchanges (https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_calls_login.htm).

 

Por lo tanto, utilizar el conector de Servicios Web no es óptimo ya que obtener un ID de sesión dinámico significa que necesita invocar primero el método de autenticación de Salesforce (a través de una autenticación con usuario, contraseña y un token de seguridad) para después, invocar el método deseado.

Para este ejemplo, el conector de servicios web puede resultar en tener que más de un llamado desde Bizagi a Salesforce y no se siguen las buenas prácticas del manejo de transacciones o de altos aspectos de seguridad cuando se manejan IDs de sesión.

Debido a lo anterior, en esta guía vamos a invocar Salesforce a través de su API de SOAP, pero a través de la  librería de componentes.

Para esta funcionalidad, desarrollaremos un componente personalizado que maneje el ID de sesión y todos los aspectos relacionados con el mecanismo de autenticación, como se encuentra disponible en Salesforce.

 

Antes de empezar

Antes de empezar con la integración ilustrada por esta guía, asegúrese de tener una cuenta válida en Salesforce.

 

Sforce_results

 

Cuando lo haga, observe que necesita otorgar acceso a su máquina, de tal forma que se permita usar su cuenta de Salesforce, como se requiere por las políticas de seguridad de Salesforce.

Usted puede autorizar dicho acceso a su cuenta de Salesforce y configurar un token de seguridad, directamente en Ajustes Personales (Personal settings) presentados en su portal de Salesforce (i.e., https://na22.salesforce.com/_ui/system/security/ResetApiTokenEdit?retURL=%2Fui%2Fsetup%2FSetup%3Fsetupid%3DPersonalInfo&setupid=ResetApiToken).

 

Sforce_securitytoken

 

¿Qué necesita hacer?

Adicionalmente a los requisitos de Salesforce, la siguiente lista ilustra un esquema de pasos que necesitan ser llevados a cabo para integrarse con Salesforce:

 

1. Cree su propio componente que se conecte a Salesforce

Este paso se hace fuera de Bizagi, utilice el IDE de su elección, por ejemplo Visual Studio, para producir una librería (una dll para la plataforma).

 

2. Registre el componente en Bizagi Studio

En este paso, utilice Bizagi Studio para importar la librería en su proyecto de Bizagi.

 

3. Configure una regla de negocio que invoque el componente

En este paso, utilice los métodos en dicho componente, de tal forma que puede invocar Salesforce desde cualquier punto de sus procesos de Bizagi.

Para completar estos pasos, necesitará haber incluido en su modelo de datos de su proceso e interfaces de usuario, las definiciones apropiadas ya sea para enviar información a Salesforce o para guardar la entrante.

 

Ejemplo

Para ilustrar cómo integrarse con Salesforce, partiremos de tener el proceso de Peticiones, quejas y reclamos como el que se encuentra disponible en Bizagi Xchange (https://www.bizagi.com/es/plataforma/xchange).

El objetivo principal de este proceso es asignar responsabilidades y hacer un seguimiento a los comentarios ingresados ya sea en una petición, una queja, un reclamo o una sugerencia; para manejarlos acordemente en toda la organización.

 

Sforce_PCC2

 

Como ejemplo, asumiremos que las peticiones de entrada son estrictamente sugerencias:

1.La persona a cargo de analizar la sugerencia ("Solucionador del caso", asignado a la tarea Analizar sugerencia) debe poder escoger crear un nuevo prospecto con los datos del solicitante.

2.Bizagi presentará una tabla con los prospectos actuales en Salesforce para el Solucionador del caso para usarla como una referencia en tiempo real.

Una vez la sugerencia ha sido analizada y asumiendo que el solicitante debe ser creado como un nuevo prospecto, Bizagi persistirá esta información en Salesforce.

 

Con todo, en esta guía se ejecutarán estos 2 puntos de integración con Salesforce agregando la configuración a la plantilla de proceso existente en las actividades Enviar Respuesta y Analizar Sugerencia.

La actividad Enviar Respuesta será el punto de integración donde Bizagi traerá todos los prospectos desde Salesforce (i.e una lectura), mientras que la actividad Analizar Sugerenciay será el punto de integración donde Bizagi enviará el nuevo prospecto (i.e una escritura).

 

note_pin

Para seguir los pasos presentados en esta sección y tener una aplicación completamente funcional de su lado, se le sugiere descargar e instalar la plantilla del proceso de Peticiones, Quejas y Reclamos desde Process Xchange.

Para más información sobre esta plantilla de proceso y cómo puede ser descargada y utilizada sin costa, consulte Bizagi Process Xchange.

 

Pasos

Los siguientes pasos y componentes son desarrollados como un ejemplo orientado a la plataforma.

 

1. Cree su propio componente que conecte con Salesforce

El primer paso antes de siquiera empezar a desarrollar el componente, es asegurarse de que ha preparado todo lo necesario para conectarse con Salesforce.

Adicionalmente, tener una cuenta y un token de seguridad como se describe antes en la sección Antes de empezar, también necesitará primero guardar la definición de dichos servicios haciéndolos disponibles para el API de SOAP de su cuenta de Salesforce.

El almacenado de la definición (el WSDL actual) se hace en su máquina local y debe ser almacenado por un Servidor Web de IIS en ejecución.

 

note_pin

Esta guía se basa en el ejemplo provisto por Salesforce en https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_quickstart_steps.htm, aunque se realizaron algunos ajustes.

Tenga en cuenta que Salesforce puede actualizar su documentación, su soporte del API o sus prácticas recomendadas en cualquier momento sin previo aviso.

Para información sobre el API SOAP de Salesforce o mayor documentación sobre sus objetos y específicos, consulte https://developer.salesforce.com/page/Sample_SOAP_Messages.

 

1.1 Localice el WSDL

Localice el WSDL iniciando sesión en el portal de Salesforce y después escribiendo API en el cuadro de búsqueda.

Dentro de los resultados de la búsqueda, busque la página Develop API:

 

Sforce_portal1

 

1.2 Guarde el WSDL

Una vez la en la página API WSDL, descargue y guarde localmente el archivo WSDL generado por los Servicios Empresariales de Salesforce, utilizando la opción "guardar enlace como..." de su navegador:

 

Sforce_portal2

 

Observe que este archivo debe tener la extensión .wsdl (además, el nombre completo para este archivo es "enterprise.wsdl").

 

1.3 Aloje el archivo en el IIS

Para hacer que el archivo esté disponible via web, guarde este archivo en la ruta local del inicio del IIS en C:\inetpub\wwwroot\.

La siguiente imagen muestra el archivo enterprise.wsdl almacenado en C:\inetpub\e wwwroot\LocalWS\:

 

Sforce_portal3

 

1.4 Modifique el WSDL

Este paso es necesario para resolver un problema conocido que tiene Salesforce con respecto a sus definiciones WSDL.

Modifique el WSDL e incluya esta línea adicional:

<xsd:attribute name="tmp" type="xsd:string" />

dentro del la definición del elemento ListViewRecord.

 

Esto significa que debe cambiar la definición original:

<complexType name="ListViewRecord">

 <sequence>

           <element name="columns" type="tns:ListViewRecordColumn" maxOccurs="unbounded"/>

 </sequence>

</complexType>

 

Por esta:

<complexType name="ListViewRecord">

 <sequence>

           <element name="columns" type="tns:ListViewRecordColumn" maxOccurs="unbounded"/>

 </sequence>

 <xsd:attribute name="tmp" type="xsd:string" />

</complexType>

 

Sforce_wsdledit

 

1.5 Verifique que el WSDL puede ser accedido desde web

En este punto, usted debe poder acceder a este WSDL a través del protocolo HTTP.

Use http://localhost/[RUTA_DE_SU_WSDL] desde el navegador de su elección, para verificar que el WSDL es accesible por web y que su estructura es un XML consistente después de haberlo modificado.

 

Como se especificó anteriormente, la siguiente imagen usa la carpeta LocalWS y por lo tanto, tiene el WSDL accesible en http://localhost/LocalWS/enterprise.wsdl:

 

Sforce_wsdl

 

1.6 Cree un nuevo proyecto de Visual Studio

Ahora que tiene todo lo necesario en Saleforce, proceda a crear el componente.

Para esto, cree una nuevo proyecto de clase de librería en la versión 4.0 del framework de .NET:

 

Sforce_visual1

 

1.7 Agregue la referencia al servicio al WSDL

Como se describe en la documentación de Salesforce, agregue una referencia al servicio (service referenc) que apuntan al WSDL alojado en el IIS:

 

Sforce_reference  

 

Observe que el namespace de la referencia del servicio ara este ejemplo, se llama sforce2.

Aunque usted puede darle que nombre que desee, tenga en cuenta que nombre sforce2 será referenciado en pasos adicionales en esta guía.

 

1.8 Agregue otras librerías

Incluya otras librerías necesarias, en especial la librería System.ServiceModel:

 

Sforce_import

 

1.9 Ajuste los parámetros del buffer

Todos los proyectos .NET utilizan por defecto unos parámetros de buffer configurados con valores bajos, dirigidos a transacciones de pequeñas cantidades de datos.

Asegúrese de ajustar dichos parámetros de tal forma que pueda permitirle a su aplicación transmitir una cantidad mayor de datos (debe ajustarlos de manera medible para un entorno de producción, ya que estos ajustes son parte de las medidas de seguridad que mitigan los ataques de denegación de servicio).

Debido a que el ejemplo de Salesforce va a buscar todas los prospectos (aunque un aproximado de 22 registros), pero junto con una gran cantidad de información de metadatos, proceda a modificar los parámetros de la memoria: maxBufferSize, maxReceivedMessageSize y maxBufferPoolSize.

 

Para esto, edite el elemento binding que se encuentra directamente en el archivo app.config de su proyecto, de tal forma que utilice los siguientes valores (o como medidas de acuerdo a la información esperada que usted va a manejar):

 

<binding name="SoapBinding"  maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferPoolSize="524288">

 <security mode="Transport" />

</binding>

 

Sforce_appconfig

 

1.10 Codifique el componente

Incluya el código para Class.cs de su proyecto de clase de librería.

Usted puede usar el siguiente código basado en la documentación de inicio rápido de Salesforce(https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_quickstart_steps_walk_through_code.htm):

 

C# codeVer código aquí
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceModel;
using System.Xml.Linq;
using MySalesforceLibrary.sforce2;

namespace MySalesforceLibrary
{
   public class Class1
   {
       private static SoapClient loginClient;
       private static SoapClient client;
       private static SessionHeader header;
       private static EndpointAddress endpoint;

       #region public Methods
       #region Tests everything this component supports
       public void Test(String userName, String password, String securityToken, String objectType,
           String firstName, String lastName, String company, String email)
       {
           if (login(userName, password, securityToken))
           {
               describeGlobals(objectType);
               queryLeads();
               createLead(firstName, lastName, company, email);

               logout();
           }
       }
       #endregion

       #region Tests the connection and fetching metadata
       public void Connect(String userName, String password, String securityToken, String objectType)
       {
           if (login(userName, password, securityToken))
           {
               describeGlobals(objectType);
               logout();
           }
       }
       #endregion

       #region Runs a query which fetches all leads
       public String Query(String userName, String password, String securityToken)
       {
           String results = "<ClaimandComplaintRequest>";
           if (login(userName, password, securityToken))
           {
               results += queryLeads();
               logout();
           }
           return results + "</ClaimandComplaintRequest>";
       }
       #endregion

       #region Creates a Lead
       public String Create(String userName, String password, String securityToken,
           String firstName, String lastName, String company, String email)
       {
           String confirmationId = "0";
           if (login(userName, password, securityToken))
           {
               confirmationId = createLead(firstName, lastName, company, email);
               logout();
           }
           return confirmationId;
       }
       #endregion
       #endregion

       #region private Methods
       #region login
       private bool login(String userName, String password, String securityToken)
       {
           // Create a SoapClient specifically for logging in
           loginClient = new SoapClient();
           LoginResult lr = null;

           try
           {
               Console.WriteLine("\nLogging in...\n");
               lr = loginClient.login(null, userName, password + securityToken);
           }
           catch (Exception e)
           {
               Console.WriteLine("An unexpected error has occurred: " + e.Message + "\nStack trace: " + e.StackTrace);
           }

           // Check if the password has expired
           if (lr.passwordExpired)
           {
               Console.WriteLine("An error has occurred. Your password has expired.");
               return false;
           }

           // On successful login, cache session info and API endpoint info
           endpoint = new EndpointAddress(lr.serverUrl);
           header = new SessionHeader();
           header.sessionId = lr.sessionId;

           // Create and cache an API endpoint client
           client = new SoapClient("Soap", endpoint);
           printUserInfo(lr, lr.serverUrl);

           return true;
       }
       #endregion

       #region printLogin
       private void printUserInfo(LoginResult lr, String authEP)
       {
           try
           {
               GetUserInfoResult userInfo = lr.userInfo;
               Console.WriteLine("UserID: " + userInfo.userId);
               Console.WriteLine("User Full Name: " + userInfo.userFullName);
               Console.WriteLine("User Email: " + userInfo.userEmail);
               Console.WriteLine();
               Console.WriteLine("SessionID: " + lr.sessionId);
               Console.WriteLine("Auth End Point: " + lr.serverUrl);
               Console.WriteLine("Service End Point: " + lr.serverUrl);
               Console.WriteLine();
           }
           catch (Exception e)
           {
               Console.WriteLine("An unexpected error has occurred: " + e.Message + "\nStack trace: " + e.StackTrace);
           }
       }
       #endregion

       #region describeGlobals
       private void describeGlobals(String myObjectType)
       {
           #region describeGlobalSample
           try
           {
               // describeGlobal() returns an array of object results that includes the object names that are available to the logged-in user.
               DescribeGlobalResult dgr;
               client.describeGlobal(header, null, out dgr);
               Console.WriteLine("\nDescribe Global Results:\n");

               // Loop through the array echoing the object names
               for (int i = 0; i < dgr.sobjects.Length; i++)
               {
                   Console.WriteLine(dgr.sobjects[i].name);
               }
           }
           catch (Exception e)
           {
               Console.WriteLine("An exception has occurred: " + e.Message + "\nStack trace: " + e.StackTrace);
           }
           #endregion

           #region describeSObjectSample
           try
           {
               string objectType = myObjectType;

               // Call describeSObjects() passing in an array with one object type name
               DescribeSObjectResult[] dsrArray;
               client.describeSObjects(header, null, null, new string[] { objectType }, out dsrArray);

               // Loop all fetched occurrences; possibly just one in this sample
               for (int arrayCount = 0; arrayCount < dsrArray.Length; arrayCount++)
               {
                   DescribeSObjectResult dsr = dsrArray[arrayCount];

                   // Get some object properties
                   Console.WriteLine("\n\nObject Name: " + dsr.name);
                   if (dsr.custom) Console.WriteLine("Custom Object");

                   // Get the permissions on the object
                   if (dsr.label != null) Console.WriteLine("Label: " + dsr.label);
                   if (dsr.createable) Console.WriteLine("Createable");
                   if (dsr.deletable) Console.WriteLine("Deleteable");
                   if (dsr.queryable) Console.WriteLine("Queryable");
                   if (dsr.replicateable) Console.WriteLine("Replicateable");
                   if (dsr.retrieveable) Console.WriteLine("Retrieveable");
                   if (dsr.searchable) Console.WriteLine("Searchable");
                   if (dsr.undeletable) Console.WriteLine("Undeleteable");
                   if (dsr.updateable) Console.WriteLine("Updateable");
                   Console.WriteLine("Number of fields: " + dsr.fields.Length);

                   //Retrieve metadata for each field
                   for (int i = 0; i < dsr.fields.Length; i++)
                   {
                       // Get the field and Write some field properties
                       Field field = dsr.fields[i];
                       Console.WriteLine("Field name: " + field.name);
                       Console.WriteLine("\tField Label: " + field.label);

                       //This next property indicates that this field is searched when using the name search group in SOSL
                       if (field.nameField) Console.WriteLine("\tThis is a name field.");
                       if (field.restrictedPicklist) Console.WriteLine("This is a RESTRICTED picklist field.");
                       Console.WriteLine("\tType is: " + field.type.ToString());
                       if (field.length > 0) Console.WriteLine("\tLength: " + field.length);
                       if (field.scale > 0) Console.WriteLine("\tScale: " + field.scale);
                       if (field.precision > 0) Console.WriteLine("\tPrecision: " + field.precision);
                       if (field.digits > 0) Console.WriteLine("\tDigits: " + field.digits);
                       if (field.custom) Console.WriteLine("\tThis is a custom field.");

                       // Write the permissions of this field
                       if (field.nillable) Console.WriteLine("\tCan be nulled.");
                       if (field.createable) Console.WriteLine("\tCreateable");
                       if (field.filterable) Console.WriteLine("\tFilterable");
                       if (field.updateable) Console.WriteLine("\tUpdateable");

                       // If this is a picklist field, show the picklist values
                       if (field.type.Equals(fieldType.picklist))
                       {
                           Console.WriteLine("\tPicklist Values");
                           for (int j = 0; j < field.picklistValues.Length; j++)
                               Console.WriteLine("\t\t" + field.picklistValues[j].value);
                       }

                       // If this is a foreign key field (reference), show the values
                       if (field.type.Equals(fieldType.reference))
                       {
                           Console.WriteLine("\tCan reference these objects:");
                           for (int j = 0; j < field.referenceTo.Length; j++)
                               Console.WriteLine("\t\t" + field.referenceTo[j]);
                       }
                       Console.WriteLine("");
                   }
               }
           }
           catch (Exception e)
           {
               Console.WriteLine("An exception has occurred: " + e.Message + "\nStack trace: " + e.StackTrace);
           }
           #endregion
       }
       #endregion

       #region queryLeads
       private String queryLeads()
       {
           string myXML = @"<Leads>";

           try
           {
               String soqlQuery = "SELECT Id, FirstName, LastName, Company, State, Email, Status, CreatedDate FROM Lead ORDER BY LastName";
               //String soqlQuery = "SELECT FirstName, LastName, OwnerId FROM Lead ORDER BY LastName";
               QueryResult qr;
               client.query(header, null, null, null, soqlQuery, out qr);
               bool done = false;

               if (qr.size > 0)
               {
                   Console.WriteLine("Logged-in user can see " + qr.records.Length + " records.");

                   while (!done)
                   {
                       Console.WriteLine("");
                       sObject[] records = qr.records;
                       for (int i = 0; i < records.Length; i++)
                       {
                           //Contact con = (Contact)records[i];
                           Lead lead = (Lead)records[i];
                           string fName = lead.FirstName;
                           string lName = lead.LastName;

                           if (fName == null) Console.WriteLine("Record #" + (i + 1) + ": " + lName);
                           else Console.WriteLine("Record #" + (i + 1) + ": " + lName + ", " + fName);

                           myXML += "<Lead><Name>" + lName + ", " + fName + "</Name><Company>"
                               + lead.Company + "</Company><StateProvince>" + lead.State + "</StateProvince><Email>"
                               + lead.Email + "</Email><LeadStatus>" + lead.Status + "</LeadStatus><CreatedDate>"
                               + String.Format("{0:yyyy-MM-ddTHH:mm:ssZ}", lead.CreatedDate) + "</CreatedDate><LeadID>"
                               + lead.Id + "</LeadID></Lead>";
                       }

                       if (qr.done) done = true;
                       else
                       {
                           client.queryMore(header, null, qr.queryLocator, out qr);
                       }
                   }
               }
               else Console.WriteLine("No records found.");
           }
           catch (Exception e)
           {
               Console.WriteLine("\nFailed to execute query succesfully," + "error message was: \n{0}", e.Message);
           }

           /*XDocument xdoc = new XDocument();
           xdoc = XDocument.Parse(myXML);
           return xdoc;*/
           return myXML + "</Leads>";

       }
       #endregion

       #region createLead
       private String createLead(String FirstName, String LastName, String Company, String Email)
       {
           String confirmationId = "0";
           try
           {
               Lead myNewLead = new Lead();
               /*myNewLead.Description = "incoming from Bizagi";
               myNewLead.Salutation = "Mr";*/
               myNewLead.FirstName = FirstName;
               myNewLead.LastName = LastName;
               myNewLead.Company = Company;
               myNewLead.Email = Email;

               sObject[] objects = { myNewLead };

               SaveResult[] results;
               LimitInfo[] limitinfo;

               client.create(
                   header,
                   null,
                   null,
                   null,
                   null,
                   null,
                   null,
                   null,
                   null,
                   null,
                   null,
                   null,
                   objects,
                   out limitinfo,
                   out results
               );
               
               SaveResult tmp = results[0];
               if (tmp.success)
               {
                   Console.WriteLine("Created lead Id is: " + tmp.id + ".");
                   confirmationId = tmp.id;
               }

           }
           catch (Exception e)
           {
               Console.WriteLine("\nFailed to execute query succesfully," + "error message was: \n{0}", e.Message);
           }
           return confirmationId;
       }
       #endregion

       #region logout
       private void logout()
       {
           try
           {
               client.logout(header);
               Console.WriteLine("Logged out.");
           }
           catch (Exception e)
           {
               Console.WriteLine("An unexpected error has occurred: " + e.Message + "\nStack trace: " + e.StackTrace);
           }
           Console.WriteLine("\nPress ENTER to continue...");
           Console.ReadLine();
       }
       #endregion
       #endregion

   }
}

 

 

 

Observe que la clase llamada Class1 ofrece 2 métodos que sirven como puntos de entrada para la lógica que Bizagi necesitará para el uso desde una perspectiva de procesos.

Estos métodos son:

public String Query(String userName, String password, String securityToken): trae todos los prospectos a partir de los parámetros de autenticación.

public String Create(String userName, String password, String securityToken, String firstName, String lastName, String company, String email): crea un nuevo prospecto a partir de los parámetros de autenticación y los 4 campos básicos y obligatorios del nuevo prospecto: el nombre, apellido, la compañía para la que trabaja y una dirección de correo electrónico.

 

Tanto el nombre de la clase (Class1) coom cada uno de los métodos anteriores, serán referenciados por el mismo nombre en pasos posteriores.

 

note_pin

Considere que todo el código es provisto como es, principalmente como un código de ejemplo que ilustra una posibilidad cuando se integra con Salesforce.

Usted puede realizar las modificaciones pertinentes para extender la funcionalidad en ella (i.e, considerar la administración de contactos, Oportunidades o cuentas, considerar cambios en las APIS o resoluciones a problemas introducidos directamente por Salesforce, o usar un archivo de configuración app.config que maneje credenciales para evitar codificación de información).

 

Para el método public String Query, el código anterior retorna una cadena de texto en formato XML que tiene la siguiente estructura:

<ClaimandComplaintRequest>

<Leads>

<Lead><Name>Akin, Kristen</Name><Company>Aethna Home Products</Company><StateProvince>VA</StateProvince><Email>kakin@athenahome.com</Email><LeadStatus>Working - Contacted</LeadStatus><CreatedDate>2015-12-28T17:07:00Z</CreatedDate><LeadID>00Q1500000sGMpKEAW</LeadID></Lead>

</Leads>

</ClaimandComplaintRequest>

La razón por la que retorna un XML es para habilitar un fácil manejo de la información directamente en Bizagi, a través del uso del API de reglas y del uso de scopes o tecnologías XPath en Bizagi.

 

1.11 Construya la librería

Construya su proyecto de tal forma que produzca la librería necesaria en Bizagi.

Haga esto asegurándose de que se genera para su arquitectura de sistema (32-bit o 64-bit) y la versión del framework de .NET:

 

Sforce_visual2

 

La imagen de arriba muestra la clase de librería MySalesforceLibrary.dll (como fue llamado por los pasos presentados anteriormente).

Recuerde dónde se genera esta clase, ya que la necesitará en pasos y configuraciones posteriores.

 

1.12 Pruebe su componente desde otro proyecto de Visual Studio

Aunque este es un paso adicional, se recomienda asegurarse del correcto funcionamiento de su componente cuando se invoca desde otro proyecto.

Este otro proyecto puede ser uno creado directamente en su solución de Visual Studio como un proyecto de consola.

 

note_pin

Observe que Bizagi puede invocar la clase de librería como lo hace un proyecto de consola, desde un punto de vista lógico.

Garantizando al mismo tiempo que no tiene errores de codificación antes de entrar en Bizagi, se consigue roundtrips más eficientes con respecto a los ajustes de código.

 

Para esto, cree un nuevo proyecto de consola a esta misma solución:

 

Sforce_visual3

 

Esto le ayudará a probar y verificar su componente (por ejemplo ver directamente en la consola los prospectos generados):

 

Sforce_outputleads

 

Asegúrese de incluir su clase de librería como referencia:

 

Sforce_testconsole

 

Después, copie y pegue exactamente el mismo contenido desde el archivo app.config del proyecto de clase de librería de Salesforce en el archivo app.config del proyecto de consola creado.

Esto significa que el app.config o el proyecto de Consola, deben tener la misma dirección del endpoint (endpoint address) y la configuración de los parámetros maxBufferSize, maxReceivedMessageSize y maxBufferPoolSize, se muestra a continuación:

 

,Sforce_appconfig

 

Para la clase principal (llamada TestConsole en este ejemplo), usted puede utilizar el siguiente código y diligenciar userName, password y securityToken:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using MySalesforceLibrary;

 

namespace TestConsole

{

   class Program

   {

       

       static void Main(string[] args)

       {

           String userName = "";                //your account's username here

           String password = "";                //your password here

           String securityToken = "";        //your security token here

           String objectType = "Lead";

 

           Console.WriteLine("Press an option (1-4) to run a test:");

           Console.WriteLine("\t" + "-> 1 to test the connection only");

           Console.WriteLine("\t" + "-> 2 to test querying all leads");

           Console.WriteLine("\t" + "-> 3 to test creating one lead");

           Console.WriteLine("\t" + "-> 4 to test all of the above");

 

           Class1 pr = new Class1();

           String option = Console.ReadLine();

           int optionInt;

           if (Int32.TryParse(option, out optionInt))

           {

               switch (optionInt)

               {

                   case 1:

                       pr.Connect(userName, password, securityToken, objectType);

                       break;

                   case 2:

                       Console.WriteLine(pr.Query(userName, password, securityToken));

                       break;

                   case 3:

                       Console.WriteLine(pr.Create(userName, password, securityToken,

                           "Jerome", "Jones", "AgilityCorp", "jj@agilitycorp.com"));

                       break;

                   case 4:

                       pr.Test(userName, password, securityToken, objectType,

                           "Jerome", "Jones", "AgilityCorp", "jj@agilitycorp.com");

                       break;

                   default:

                       Console.WriteLine("Not a valid option. Ending execution.");

                       break;

               }

           }

       }

   }

}

 

Ejecutando el proyecto de consola con el código anterior, le permitirán probar separadamente tanto la conexión como todos los métodos usados en este ejemplo (o puede extender estas posibilidades si implementa métodos adicionales):

 

Sforce_outputtest

 

2. Registre el componente en Bizagi Studio

Una vez haya construido la clase de librería y haya verificado que funciona correctamente, abra su proyecto de Bizagi Studio.

 

2.1 Abra la librería de componentes

Navegue a la pestaña de Herramientas en la cinta de opciones y dé clic en la opción Librería de componentes.

Dé clic en Agregar para registrar su componente de Salesforce:

 

Sforce_Bizagi1

 

2.2 Ingrese los detalles del componente

Ingrese los detalles de Nombre visual y Descripción.

Por último, localice y cargue la clase de librería, la cual en este ejemplo es MySalesforceLibrary.dll:

 

Sforce_Bizagi2

 

Dé clic en Finalizar y después en Ok.

 

2.3 Ingrese los detalles del componente

De la misma forma como se hizo con el Proyecto de Consola de Pruebas, necesita utilizar las mismas definiciones que le permitan a Bizagi como aplicación, ejecutar y trasmitir servicios de Salesforce.

Para esto, copie el contenido del archivo app.config del proyecto de la clase de librería de Salesforce, específicamente, aquellos dentro del elemento <system.serviceModel>, los cuales son <bindings> y <client>.

 

Sforce_Webconfig2

 

Desde el explorador de Windows, localice el archivo web.config de Bizagi y edítelo (por defecto en C:\Bizagi\Projects\[su_proyecto]\WebApplication).

Para editarlo, primero localice el elemento <system.serviceModel> y después, copie dicho contenido dentro del mismo:

 

Sforce_Webconfig

 

Guarde el archivo cuando termine.

A partir de este punto, el componente ha sido empaqueta y puede ser usado libremente en cualquier regla de negocio de sus procesos.

 

note_pin

De acuerdo con la configuración realizada anteriormente, la forma de utilizar los métodos 2 en una regla de negocio es:

MySalesforceLibrary.Class1.Query(...)

MySalesforceLibrary.Class1.Create(...)

 

3. Configure una regla de negocio que invoque su componente

Antes de configurar cualquier regla de negocio para utilizar el componente registrado, necesitará asegurarse previamente de que tiene las definiciones apropiadas en el modelo de datos y las opciones de Interfaz gráfica para manejar la información de Salesforce (i.e., los campos para el nombre del prospecto, el correo electrónico y la compañía en Bizagi).

Para ilustrar esta parte y producir una aplicación completamente ejecutable, recuerde que haremos cambios necesarios en la plantilla del proceso Peticion, Quejas y Reclamos que se descargó desde el Process Xchange.

 

3.1 Cree una entidad llamada Prospecto (Lead)

Edite el modelo de datos para que desde ahora tenga una entidad llamada Prospecto (Lead).

Para esto, vaya al diagrama del Modelo de datos del proceso (asistente del proceso paso #2) y cree una nueva entidad maestra:

 

Sforce_model2

 

3.2 Cree los atributos para la entidad

La información de la entidad Prospecto debe coincidir con la información del prospecto en Salesforce que esté considerada por el componente.

Por lo tanto, cree los siguientes atributos que corresponden a aquellos usados por el código provisto en el ejemplo: Nombre (Name), Compañía (Company), Estado (StateProvince), Correo Electrónico (Email), Estado del prospecto (LeadStatus) y Fecha de creación (CreatedDate).

 

Sforce_model1

 

3.3 Cree una entidad de relación

Cree una nueva relación para conectar el modelo actual de datos (desde la entidad de proceso llamada Solicitud de Quejas y Reclamos (Claim and Complaint request), con la entidad Prospecto (Lead) recientemente creada.

Para esto, dé clic en la opción Relación:

 

Sforce_model3

 

Para esta relación, asegúrese de seleccionar Solicitud de Quejas y Reclamos (Claim and Complaint request) como la Entidad 1 y Prospecto (Lead) como la Entidad 2:

 

Sforce_modelR1

 

Después, Selección la opción Colección (Uno-Muchos).

Esto le permite a las interfaces de usuario, presentar una tabla con la lista de prospectos, estos serán traídos a Bizagi desde Salesforce.

Bizagi llamará esta relación Prospectos (Leads).

 

Sforce_modelR3

 

Ahora que los cambios en el modelo de datos han sido completados, el diagrama del modelo debe mostrar la nueva relación que conecta la entidad Solicitud de quejas y reclamos (Claim and Complaint request) con la entidad Prospecto (Lead):

 

 

Sforce_model5

 

3.4 Abra las formas

Procederemos ahora a editar las interfaces de usuario existentes.

Para esto, vaya al paso #3 del asistente de proceso llamado Definir formas, y abra la forma de la actividad Analizar sugerencia (Analyse suggestion):

 

Sforce_Bizagi3

 

Tenga en cuenta que puede usar la información del solicitante que ya está almacenada en este punto (este conjunto de información es el que será enviado como un nuevo prospecto en Salesforce).

Por lo tanto, ajuste las interfaces de usuario para presentar la posibilidad de crear un Prospecto en Salesforce, solo necesita un botón con su acción respectiva.

 

3.5 Agregue un nuevo botón

Localice el control de Botón para agregarlo al grupo de información del solicitante:

 

Sforce_Bizagi6

 

Asegúrese de configurar su Etiqueta y la Etiqueta del botón y después, dé clic en Acciones y validaciones para definir la acción cuando se hace clic:

 

Sforce_Bizagi7

 

3.6 Defina la acción del botón

Agregue una nueva acción, la cual lanzará la integración con Salesforce cuando se da clic al botón Crearlo como Prospecto (Create as lead).

Configure la acción para ejecutar una regla, tal como se muestra a continuación:

 

Sforce_Bizagi9

 

Para la configuración del argumento, cree una nueva regla de negocio:

 

Sforce_Bizagi8

 

El código de la regla debe tener:

var myComponent = new MySalesforceLibrary.Class1();

myComponent.Create("", "", "",

 <ClaimandComplaintRequest.Customer.FirstName>,

 <ClaimandComplaintRequest.Customer.LastName>,

 "Agility Corp.",

 <ClaimandComplaintRequest.Customer.CustomerSnapshot.Email>);

 

note_pin

Tenga en cuenta que este código instancia el componente al invocar sus métodos con esta sintaxis: MySalesforceLibrary.Class1.Create(...).

Recuerde que este código necesitará ingresar el nombre de Usuario, la contraseña y el token de seguridad de su propia cuenta de Salesforce.

 

Guarde la regla asegurándose de que no hay errores mostrados en Bizagi.

La nueva acción debe verse de manera similar a esta:

 

Sforce_Bizagi10

 

Aunque a este punto usted ya ha verificado la conexión con Salesforce desde Bizagi y creó prospectos utilizando el botón, vamos a ilustrar cómo configurar la parte en que se traen todos los prospectos.

 

3.7 Incluya una tabla para todos los prospectos

En la misma forma de la actividad, cree una pestaña adicional

 

Sforce_Bizagi4

 

Tenga en cuenta que la puede nombrar como "Prospectos Salesforce" o con el nombre de su elección, aunque la parte más relevante es asegurarse que incluyó la relación Prospectos (Leads) de su modelo de datos (i.e una colección, para ser mostrada por Bizagi como una tabla en tiempo de ejecución).

 

3.8 Configure la tabla

Establezca las propiedades de la tabla como de solo lectura (i.e es decir, Opciones de borrado, Opciones de adición y Opciones de fila deshabilitadas) después, incluya la información relevante del prospecto (Nombre (Name), Compañía (Company), Estado (StateProvince), Correo electrónico (Email), Estado del prospecto (LeadStatus) y fecha de creación (CreatedDate)), como se muestra a continuación:

 

Sforce_Bizagi5

 

Cierre y guarde la forma cuando termine.

 

3.9 Configure la regla de negocio desde las acciones de la actividad.

Vaya al asistente del proceso en el paso 4 llamado Acciones de la actividad.

 

Sforce_Step4

 

Agregue una nueva acción a la actividad en el tiempo Al Salir de la actividad Enviar Respuesta (Send Answer):

 

Sforce_AA1

 

Cree una nueva regla de negocio que tenga este código:

var myComponent = new MySalesforceLibrary.Class1();

var result = myComponent.Query("", "", "");

CEntityXmlHelper.fromXmlToEntityWithScopes(Me, result,false);

 

Sforce_Rule2

 

Guarde la regla siempre que se asegure de que no hay errores mostrados por Bizagi. Y eso es todo.

 

note_pin

Usted puede mejor el ejemplo presentado, el cual es solo con propósitos ilustrativos.

 

Por ejemplo y para una implementación en vivo, usted puede considerar estos aspectos más avanzados:

Para el componente, se espera y se sugiere usar un archivo .config file para permitir una rigurosa seguridad y mejor manejo de las credenciales de las cuentas de servicio y el token de seguridad, en vez de quemarlas en la regla de negocio.

En Bizagi, se le recomienda usar integración asíncrona con Salesforce, para utilizar una entidad adicional en el medio que conecte la entidad de proceso con prospecto (Lead) y no directamente, y así usar transformaciones XLST.

Dependiendo de sus requerimientos, usted podría querer extender este ejemplo y modificar ambos componentes en Bizagi. Por ejemplo, puede agregar más atributos como el ID retornado por el prospecto creado en Salesforce, permitir entradas dinámicas para el nombre del a compañía o enviar información adicional a Salesforce (como números de teléfono, localización, etc).

 

Ejecución

Ejecute su proceso utilizando el botón Ejecutar en Bizagi Studio.

Una vez se abra el Portal de Trabajo de Bizagi en el navegador, cree un nuevo caso del proceso Peticiones, quejas y reclamos:

 

Sforce_Execute0

 

En la primera tarea llamada Recibir solicitud (Receive request), usted diligenciará los detalles del solicitante (documento, nombre, correo electrónico) y asegúrese de seleccionar que la solicitud es una Sugerencia.

 

Sforce_Execute2

 

Dé clic en Siguiente cuando termine.

Usted verá a Bizagi en espera por un momento mientras trae los registros desde Salesforce.

 

En la tarea Analizar Sugerencia (Analyze Suggestion), usted puede ver todos los prospectos desde la pestaña Prospectos de Salesforce o utilizar el botón Crear como Prospecto para crear uno nuevo:

 

Sforce_Execute1

 

Ver todos los prospectos:

 

Sforce_Execute3

 

Cuando cree un nuevo prospecto, usted puede verificar su creación en el portal de Salesforce:

 

Sforce_Execute4

 

Tips para solución de problemas

Como se dijo previamente, se recomienda que se pruebe el componente en Bizagi una vez haya validado completamente que los métodos del mismo funcionen correctamente cuando fueron invocados desde otro proyectos de Visual Studio.

Una vez haya verificado esto y para solucionar problemas mientras se esté usando en Bizagi, depure el componente usando la opción "Adjuntar al proceso..." como se entrega con Visual Studio.

Para ello, tenga en cuenta que debe adjuntar a un proceso de IIS que ejecuta w3wp.exe:

 

Sforce_troubleshooting

 

Para esto, usted necesitará asegurarse de que la salida del componente esté empaquetada en Bizagi en modo Debug (Esto solo para ser usado en ambientes de desarrollo para propósitos de solución de problemas).

 

Cuando haga los cambios al componente y reconstruya su salida, asegúrese de cargar de nuevo esta librería en Bizagi Studio.

Para forzar que se tomen todos los cambios, puede reiniciar los servicios de IIS y borrar los archivos temporales o las versiones anteriores de los archivos dll de sus componentes.

 

note_pin

Si tiene el siguiente error "Could not find default endpoint element that references contract 'sforce2.Soap' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element." tenga en cuenta que necesita llevar a cabo los cambios en el archivo de configuración del portal de trabajo de Bizagi (web.config) como se describió cuando se registró el componente.