on Tue Sep 19 2017
Si echaste un vistazo a la publicación «Utilizando el servicio SOAP de Salesforce desde NodeJS» te habrás percatado que resulta complicado utilizar la librería soap_salesforce sin implementar una clase que gestione y aproveche recursos y encapsule algunos procedimientos repetitivos (como la gestión de las sesiones activas en Salesforce o la transformación de un objeto Javascript a sObject).
Esto es así, dado que la finalidad de dicha librería era simplemente la de enmascarar el procedimiento de autenticación contra el servicio web. No obstante en un proyecto real, es imperativo evitar la repetición de algunos procedimientos que pueden hacer que la lógica de nuestra aplicación sea difícil de leer e interpretar.
Para solucionar esto, y crear un entorno de trabajo más eficaz, publiqué hace algunos meses la librería salesforce_orm en NPM, la cual desarrollaremos brevemente en este post.
Como siempre, los prerequisitos que debemos cumplir son mínimos, basta con tener instalado NodeJS, NPM, y tener a mano nuestras credenciales de acceso a Salesforce, el token de autenticación a la API, y el fichero WSDL que describe el servicio SOAP.
Igual de sencillo es el proceso de instalación de la librería, que puede ser descargada a través del gestor de paquetes NPM:
npm install --save salesforce_orm
Al igual que en la mayoría de librerías, antes de poder utilizar salesforce_orm, deberemos instanciarla, e indicar como parámetros del constructor nuestras credenciales de acceso a Salesforce, así como el token de acceso a la API, y la ruta donde se encuentra el fichero WSDL.
let Salesforce = require('salesforce_orm');
let username = '[email protected]';
let password = 'yourPassword';
let token = 'yourToken';
let wsdlPath = __dirname+'/config/production.wsdl.xml';
let salesforce = new Salesforce(username, password, token, wsdlPath);
Tal y como su nombre indica, salesforce_orm actúa como un punto intermedio entre Salesforce y nuestra aplicación, y nos provee de una estructura ORM, donde podemos efectuar cambios y consultas sobre la base de datos de Salesforce, trabajando directamente con los objetos que la conforman. Así,
podemos modificar, por ejemplo, el nombre de una cuenta, e invocar el método «update» sobre ella, para que se actualice en el CRM directamente.
No obstante, para que esto sea posible el sistema requiere conocer la estructura de los objetos sobre los que vamos a trabajar, y aunque esto podría realizarse de forma automática, por el momento es necesario declarar los modelos de datos de forma manual.
this.salesforce.addModel({
name: 'Account',
fields: ["Id", "Name"] //Add here all API Names of Account fields
});
Ahora que hemos definido el modelo de datos (nótese que lo anterior era un ejemplo, y para que la aplicación funcione según lo esperado, deberemos indicar todos los campos que deseamos obtener y/o modificar), podemos empezar a utilizar salesforce_orm. Para ello, deberemos instancia un objeto,
es decir: Transformar un objeto Javascript normal y corriente, y dotarlo de funcionalidades para que represente un registro real de Salesforce, y para que cualquier cambio que realicemos sobre él, se refleje inmediatamente sobre nuestro CRM.
let newObjectInstance = salesforce.instanceNewObject('Account');
El código anterior creará un nuevo objeto de tipo Account en la variabe «newObjectInstance», pero…
¿Qué sucede si ya disponemos de un objeto con los campos relativos a Salesforce? Muy sencillo, veamos un ejemplo:
let existentObjectInstance = salesforce.instanceExistentObject(
'Account',
{ Id: '1234567890123456' }
); //Here you can pass any model's properties
Una vez tenemos un objeto javascript, instanciado mediante salesforce_orm, si queremos dotar a este objeto de la información de un registro de Salesforce concreto, basta con que le definamos la propiedad «Id» al identificador de Salesforce correspondiente, e invoquemos al método get, de la siguiente forma.
existentObjectInstance.get().then(()=>{
console.log(`Hello world! My name is ${existentObjectInstance.Name}`);
});
Si queremos crear un nuevo registro, es aún más sencillo. Bastará con cumplimentar todas las propiedades del objeto de Salesforce que sean obligatorias, e invocar el método «create».
newObjectInstance.Name = 'My awesome new account';
newObjectInstance.create().then(()=>{
console.log(`Hello world! My new account's name is ${newObjectInstance.Name}`);
});
En caso de querer actualizar un objeto ya instanciado, y que dispone del parámetro «Id» definido, tenemos a nuestra disposición el método «update».
existentObjectInstance.Name = `${existentObjectInstance.Name} (edited)`;
existentObjectInstance.update().then(()=>{
console.log(`Oh! My existent account has been edited and its name is now ${existentObjectInstance.Name}`);
});
En la misma línea, podemos eliminar un registro llamando al método «remove», siempre que el objeto tenga definido el parámetro «Id».
existentObjectInstance.remove().then(()=>{
console.log(`I'm so sad D=, an account has been removed from Salesforce.`);
});
Por último, es posible buscar registros de forma sencilla, tal y como se muestra en el ejemplo. Esta acción retornará un array de objetos, donde encontraremos los registros que cumplen con los parámetros de búsqueda especificados.
El segundo parámetro, hace referencia a las cláusulas de búsqueda, y en él pueden indicarse cláusulas tal y como se indicarían en una consulta SOQL habitual.
salesforce.search("Account", "Name = 'My awesome new account'").then((records)=>{
console.log(`${records.length} records have been found.`);
for(let i in records){
let record = records[i];
console.log(`${record.Name} found! (${record.Id})`);
//And here magic happens... Feel free to use all available methods (as delete or update) with these results...
record.Name = 'Changed name';
record.update();
}
});
Cabe mencionar, que este comando puede recibir un tercer parámetro donde podemos indicar campos adicionales a recuperar (además de los especificados en el fichero que inicializa el modelo de datos). Este tercer parámetro es útil para indicar por ejemplo, campos obtenidos a través de campos relacionales (lookup). Su uso podría ser similar a lo siguiente:
let additionalFields = ["Contract__r.ContractNumber"];
salesforce.search("Account", "Name = 'My awesome new account'", additionalFields).then((records)=>{});
Siguiendo el ejemplo anterior, cada uno de los registros retornados por la búsqueda, tendrá (en caso de disponer de un Contrato relacionado) los parámetros «Contract__r» y en el interior de éste, el parámetro «ContractNumber».