Aviso:

Para brindarle información de soporte completa de manera más rápida, el contenido de esta página ha sido traducido al español mediante traducción automática. Para consultar la información de soporte más precisa, consulte la versión en inglés de este contenido.

Configurar la función de Integration

A continuación, comenzaremos a codificar la lógica de ejecución del bot de comercio electrónico configurando la función de Integration que inicializamos anteriormente.

El directorio de la función, functions/ecommerce_function contiene:

  • El archivo principal de la función index.js
  • Los archivos de funciones handler de ConvoKraft
  • El archivo de configuración catalyst-config.json
  • Módulos de Node
  • Archivos de dependencias package.json y package-lock.json

Agregaremos código en las funciones handler: execute.js, fallback.js, failure.js, welcome.js, así como el archivo principal index.js.

Copia y pega el código que se muestra a continuación cuidadosamente en los archivos respectivos usando cualquier IDE de tu elección y guárdalos.

execute.js
copy
import logger from "./logger.js";
import fetch from "node-fetch";
import catalyst from "zcatalyst-sdk-node";

// Función para realizar solicitudes GET async function get(url, headers) { const response = await fetch(url, { method: ‘GET’, headers: headers }); return await response.json(); } function getRandomNumber(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }

// Función para realizar solicitudes POST async function post(url, headers, body) { const response = await fetch(url, { method: ‘POST’, headers: headers, body: JSON.stringify(body) }); return await response.json(); }

// Función para realizar solicitudes PUT async function put(url, headers, body) { const response = await fetch(url, { method: ‘PUT’, headers: headers, body: JSON.stringify(body) }); return await response.json(); }

async function getCRMToken(request) { const catalystApp = catalyst.initialize(request); var connector = catalystApp.connection({ CRMTOKEN: { client_id: `${process.env.client_id}`, client_secret: `${process.env.client_secret}`, auth_url: `${process.env.auth_url}`, refresh_url: `${process.env.refresh_url}`, refresh_token: `${process.env.refresh_token}` } }).getConnector(‘CRMTOKEN’); let accessTokenResponse=await connector.getAccessToken().then((accessToken) => { //console.log(“Inside accesstoken”+accessToken); return accessToken; }); return accessTokenResponse; } // Función para invocar URL async function invokeURL(options) { if (options.type === ‘GET’) { const response = await get(options.url, options.headers); return response; } else if (options.type === ‘POST’) { const response = await post(options.url, options.headers, options.body); return response; } else if (options.type === ‘PUT’) { const response = await put(options.url, options.headers, options.body); return response; } else { throw new Error(`Unsupported HTTP method: ${options.type}`); } }

// Manejar la funcionalidad de ejecución export default async function handleExecute(request) { logger.info(‘Handling execute request with params : ‘+JSON.stringify(request)); logger.info(‘Action NameSpace : ‘+request.action.namespace); logger.info(‘Params : ‘+JSON.stringify(request.params)); logger.info(‘Broadcast : ‘+JSON.stringify(request.broadcast)); const result = {};

const cardlist = []; switch(request.action.namespace) { case “listofitems_2”: logger.info(‘Inside NameSpace ‘+request.action.namespace);

const executeViewItemsLogic = async () => {

//let zohocrmapiurl=process.env.crmapiurl;
console.log("ENV VARIABLE "+JSON.stringify(process.env));
//console.log("Client ID"+`${process.env.client_id}`);
 const token=await getCRMToken(request);
//console.log("ACCESSTOKEN RESP : "+token);
const accessToken = 'Zoho-Oauthtoken ' + token;
logger.info('Access Token :  '+accessToken);
const header_data = new Map();
header_data.set('Content-Type', 'application/json');
header_data.set('Authorization', accessToken);
const CRMresponse = await invokeURL({
  url: 'https://'+process.env.crmapiurl+'/crm/v2/EcomProducts?fields=Name,Product_image_url,Price,Inventory_Count,Product_image',
  type: 'GET',
  headers: header_data
});

logger.info(“Response for list of items “+ JSON.stringify(CRMresponse)); const productNote = { “type”: “note”, “content”: “List of items available are listed as follows” }; cardlist.push(productNote);

for (const record of CRMresponse.data) {
  logger.info('RECPORD INFO :  '+JSON.stringify(record));
  const name = record.Name;
  const price = record.Price;
  const product_id = record.id;
  const image = record.Product_image;
  const inventory = record.Inventory_Count;
  const listItem = {
    "type": "list",
    "format": "bullet",
    "elements": [
      { "label": `Name : ${name}` },
      { "label": `Total Price : $ ${price}` },
      { "label": `Product ID : ${product_id}` },
      { "label": `Stock : ${inventory}` }
    ]
  };
  const productPic = {
    "type": "image",
    "content": image
  };
  cardlist.push(productPic);
  cardlist.push(listItem);
  logger.info('Card List : : : :'+JSON.stringify(cardlist));
}

result.card= cardlist;
result.message= "List of Objects in response";
logger.info('Result Obj inside the : : : ' + result);
logger.info('Result OF MAP : : : :'+JSON.stringify(result));

};

await executeViewItemsLogic(); logger.info(‘Result Obj before return : : : ’ + JSON.stringify(result)); return result; break; case “vieworderdetails_3”: logger.info(‘Inside NameSpace ’ + request.action.namespace);

const executeViewOrderLogic = async () => { const token=await getCRMToken(request); var cxemail=request.params.cxemail; const accessToken = ‘Zoho-Oauthtoken ’ + token; logger.info(‘Access Token: ’ + accessToken); const header_data = new Map(); header_data.set(‘Content-Type’, ‘application/json’); header_data.set(‘Authorization’, accessToken); let resp={} try{
resp = await invokeURL({ url: ‘https://’+process.env.crmapiurl+’/crm/v4/Orders/search?criteria=((Email:equals:’ + cxemail + ‘))’, type: ‘GET’, headers: header_data }); }catch(er) { logger.info(‘ERROR WHILE CRM DATA SEARCH ’ + er); } logger.info(‘Response: ’ + JSON.stringify(resp)); let items_count = 0;

  for (const order of resp.data) {
    items_count++;
    logger.info('Inside Resp Iterator - Item count : '+items_count+' Order details : '+JSON.stringify(order));
    const order_id = order.id;

    const CRMresponse = await invokeURL({
      url: 'https://'+process.env.crmapiurl+'/crm/v3/Orders/' + order_id,
      type: 'GET',
      headers: header_data
    });
    logger.info("CRMRESPONSE : : : :"+JSON.stringify(CRMresponse.data[0].product_image_url));
    const orderid = order.OrderID;
    const name = order.Name;
    const contact = order.Contact_No;
    const email = order.Email;
    const product_name = order.Product_Name;
    const price = order.Price;
    const delivery_date = order.Expected_Delivery_Date;
    const delivery_address = order.Delivery_Address;
    const order_status = order.Order_Status;

    const listItem = {
      "type": "list",
      "format": "bullet",
      "elements": [
        { "label": "Name: " + name },
        { "label": "Contact No: " + contact },
        { "label": "Email ID: " + email },
        { "label": "Product Name: " + product_name },
        { "label": "Total Price: $" + price },
        { "label": "Expected Delivery Date: " + delivery_date },
        { "label": "Delivery Address: " + delivery_address },
        { "label": "Order Status: " + order_status }
      ]
    };

    const productNote = {
      "type": "note",
      "content": items_count + ") Your order details for order id : " + orderid + " are listed as follows: "
    };

    const productPic = {
      "type": "image",
      "content": CRMresponse.data[0].product_image_url
    };

    cardlist.push(productNote);
    cardlist.push(productPic);
    cardlist.push(listItem);
    logger.info("CARD LIST : : : "+JSON.stringify(cardlist));
  }

  result.card = cardlist;

// definir broadcast
result.broadcast = {
  "cxemail": cxemail
};

result.message = "The Shoppers Stores. You don't have an order.";
logger.info("Result JSON : : : "+JSON.stringify(result));

};

await executeViewOrderLogic(); //logger.info(‘Result Obj before return: ’ + JSON.stringify(result)); return result;

break; case “placeanorder_4”: logger.info(‘Inside NameSpace ’ + request.action.namespace);

const executePlaceOrderLogic = async () => { const placeorder = {}; const token=await getCRMToken(request); const accessToken = ‘Zoho-Oauthtoken ’ + token; logger.info(‘Access Token: ’ + accessToken); const header_data = new Map(); header_data.set(‘Content-Type’, ‘application/json’); header_data.set(‘Authorization’, accessToken);

try {
  const CRMresponse = await invokeURL({
    url: 'https://'+process.env.crmapiurl+'/crm/v2/EcomProducts/' + request.params.productid,
    type: 'GET',
    headers: header_data
  });
  logger.info('CRM Response: ' + JSON.stringify(CRMresponse));

  if (CRMresponse.data == null && CRMresponse.status != 'error') {
    const stock_count = 0;
    logger.info('Empty response. Stock count reset.');
    placeorder.put('Stock', 'Empty');
  } else {
    const recordid = CRMresponse.data[0].id;
    let stock_count = CRMresponse.data[0].Inventory_Count;
    const imageurl = CRMresponse.data[0].Product_image;
    const productname = CRMresponse.data[0].Name;
    const price = CRMresponse.data[0].Price;

logger.info(recordid+” “+stock_count+” “+imageurl+” “+productname+” “+price); if (stock_count > 0) { stock_count = stock_count - 1; const reduceStock = { id: recordid, Inventory_Count: stock_count }; const updatedata = [reduceStock]; const updatedatamap = { data: updatedata };

const updateResp = await invokeURL({ url: ‘https://’+process.env.crmapiurl+’/crm/v2/EcomProducts’, type: ‘PUT’, body: updatedatamap, headers: header_data }); logger.info(‘Update Response: ’ + JSON.stringify(updateResp));

placeorder.Name = productname + ’ ’ + request.params.cxdate; // Asignar el valor usando notación de punto placeorder.Product_Name = productname; // Asignar el valor usando notación de punto placeorder.Email = request.params.cxemail; // Asignar el valor usando notación de punto placeorder.Delivery_Address = request.params.cxaddr; // Asignar el valor usando notación de punto placeorder.Expected_Delivery_Date = new Date(request.params.cxdate).toLocaleDateString(); // Asignar el valor usando notación de punto placeorder.product_image_url = imageurl; // Asignar el valor usando notación de punto placeorder.Price = price; // Asignar el valor usando notación de punto const orderID = request.params.productid + ‘_’ + getRandomNumber(1111111, 9999999); //placeorder.put(‘OrderID’, orderID); placeorder.OrderID = orderID; placeorder.Order_Status = ‘Reviewing the Order’; // Asignar el valor usando notación de punto

const insertdatamap = { data: [placeorder] }; logger.info(“INSERT MAP : : :"+JSON.stringify(insertdatamap)); const insertResp = await invokeURL({ url: ‘https://’+process.env.crmapiurl+’/crm/v2/Orders’, type: ‘POST’, body: insertdatamap, headers: header_data }); logger.info(‘Insert Response: ’ + JSON.stringify(insertResp));

      result.message =
        'Your order for the product - ' +
        CRMresponse.data[0].Name +
        ' is placed successfully. It will be tried to be delivered on ' +
        request.params.cxdate +
        ' to ' +
        request.params.cxaddr +
        '. Our Sales team will reach out to you via email to discuss COD or prepayment before delivery.';
    } else {
      result.message = 'The item is out of stock. Please retry after some days as we restock.';
    }
  }
} catch (e) {
  logger.info(e.lineNo);
  logger.info(e.message);
  logger.info(e);
  result.message = 'There was some issue during the order. Please contact the support team. They shall assist in placing this order for you.';
}

result.broadcast = { cxemail: request.params.cxemail };

};

await executePlaceOrderLogic(); return result; break; case “changedeliveryaddress”: // Nuevo caso para “changedeliveryaddress” logger.info(‘Inside NameSpace ’ + request.action.namespace);

const executeChangeDeliveryAddressLogic = async () => { const token=await getCRMToken(request); const cxorderid = request.params.cxorderid; const cxaddr = request.params.cxaddr; const cxemailid = request.params.cxemail; const accessToken = ‘Zoho-Oauthtoken ’ + token; logger.info(‘Access Token: ’ + accessToken); const header_data = new Map(); header_data.set(‘Content-Type’, ‘application/json’); header_data.set(‘Authorization’, accessToken); let searchOrderResp={}; try{ searchOrderResp = await invokeURL({ url: ‘https://’+process.env.crmapiurl+’/crm/v4/Orders/search?criteria=((OrderID:equals:’ + cxorderid + ‘))’, type: ‘GET’, headers: header_data }); }catch(e) { logger.info(“ERROR DURING SEARCH ORDER : : “+e); searchOrderResp={}; } logger.info(“Result of search Order: : : “+JSON.stringify(searchOrderResp)); if(searchOrderResp.data!=undefined) {

const recordId = searchOrderResp.data[0].id;
//logger.info("Result of search Order: : : "+JSON.stringify(searchOrderResp.data[0]));
const recordEmail=searchOrderResp.data[0].Email;
const recordorderId=searchOrderResp.data[0].OrderID;
if(cxemailid == recordEmail &&  cxorderid == recordorderId)
{
const updateData = [
  {
    id: recordId,
    Delivery_Address: cxaddr
  }
];

const updateDataMap = {
  data: updateData
};

const updateResp = await invokeURL({
  url: 'https://'+process.env.crmapiurl+'/crm/v2/Orders',
  type: 'PUT',
  body: updateDataMap,
  headers: header_data
});
logger.info('Update Response: ' + JSON.stringify(updateResp));

result.message = 'Delivery address updated successfully.';

} else{ result.message=‘Given Order ID or Email is not proper. Please check and retry’; } } else { result.message=‘Given Order ID or Email is not proper. Please check and retry’; } };

await executeChangeDeliveryAddressLogic(); return result; break; case “rescheduleorderdate”: logger.info(‘Inside NameSpace ’ + request.action.namespace);

const executeChangeDeliveryDateLogic = async () => { const token=await getCRMToken(request); const accessToken = ‘Zoho-Oauthtoken ’ + token; logger.info(‘Access Token: ’ + accessToken); const header_data = new Map(); header_data.set(‘Content-Type’, ‘application/json’); header_data.set(‘Authorization’, accessToken); const cxemailid = request.params.cxemail; const cxorderid = request.params.cxorderid; let searchOrderResp={}; try{ searchOrderResp = await invokeURL({ url: ‘https://’+process.env.crmapiurl+’/crm/v2/Orders/search?criteria=((OrderID:equals:’ + request.params.cxorderid + ‘))’, type: ‘GET’, headers: header_data }); }catch(e) { searchOrderResp={}; } if(searchOrderResp.data!=undefined){ logger.info(“Result of search Order: : : “+JSON.stringify(searchOrderResp.data[0])); const recordId = searchOrderResp.data[0].id; const recordEmail=searchOrderResp.data[0].Email; const recordorderId=searchOrderResp.data[0].OrderID; if(cxemailid == recordEmail && cxorderid == recordorderId) { const datemap = { id: recordId, Expected_Delivery_Date: new Date(request.params.cxdate).toLocaleDateString() };

const updatedata = [datemap];
const updatedatamap = {
  data: updatedata
};
logger.info("update Map : : : "+JSON.stringify(updatedatamap));
const updateResp = await invokeURL({
  url: 'https://'+process.env.crmapiurl+'/crm/v2/Orders',
  type: 'PUT',
  body: updatedatamap,
  headers: header_data
});

logger.info(“updateResponse : : : “+JSON.stringify(updateResp)); result.broadcast = { cxemail: request.params.cxemail }; result.message = ‘Your order has been rescheduled successfully.’; }else{ result.message=‘Given Order ID or Email is not proper. Please check and retry’; } } else{ result.message=‘Given Order ID or Email is not proper. Please check and retry’; } };

await executeChangeDeliveryDateLogic(); return result; break; default : result.message=‘Given request is invalid. Please check and retry’; return result; break; } //return response; }

View more

welcome.js
copy
import logger from "./logger.js";
// Manejar la funcionalidad de bienvenida
export default function handleWelcome() {
  logger.info('Handling welcome request');
  return {
    "welcome_response": {
      "message": "Welcome to your Bot. Please ask your queries"
    }
  };
}

View more

failure.js
copy
import logger from "./logger.js";

// Manejar la funcionalidad de fallo export default function handleFailure() { logger.info(‘Handling failure request’); const result = { “message”: “Something went wrong while checking your query. Please try again later.” }; return JSON.stringify(result); }

View more

fallback.js
copy
import logger from "./logger.js";
// Manejar la funcionalidad de respaldo
export default function handleFallback() {
  logger.info('Handling fallback request');
  const result = {
    "message": "Sorry couldn't get that."
  };
  return JSON.stringify(result);
}

View more

index.js
copy
import logger from './logger.js';
import IntegResponse from './integ-response.js';
import handleWelcome from './welcome.js';
import handleFallback from './fallback.js';
import handleExecute from './execute.js';
import handleFailure from './failure.js';

export default async (request, response) => { let jsonResponse = {};

try { logger.info(‘REQUEST FLOW FOR : : : ’ + request.todo); switch (request.todo) { case “welcome”: jsonResponse = handleWelcome(); break; case “execute”: jsonResponse = await handleExecute(request); break; case “fallback”: jsonResponse = handleFallback(); break; case “failure”: jsonResponse = handleFailure(); break; default: jsonResponse = JSON.stringify({ “message”: “Error Trying to parse your details” }); } } catch (err) { logger.error(‘Error while executing handler: ’ + err); logger.error(‘REQUEST OBJECT: ’ + JSON.stringify(request));

jsonResponse = JSON.stringify({
  "message": "Error Trying to parse your details"
});

} //La respuesta debe ser encapsulada en un objeto IntegResponse response.end(new IntegResponse(jsonResponse)); };

View more

Nota: Por favor, revisa todos los códigos dados en esta sección para asegurarte de que los entiendes completamente.

Repasemos rápidamente cada uno de los archivos de funciones y la lógica codificada en ellos:

  1. execute.js: Este archivo contiene la lógica principal de ejecución de todas las acciones de nuestro bot de comercio electrónico. Todas estas acciones autentican tu cuenta de Zoho CRM usando las variables de entorno configuradas y obtienen los detalles necesarios o realizan las acciones enumeradas a continuación, según sea necesario. Configuraremos las variables de entorno para la función ecommerce_function de Catalyst directamente desde la consola de Catalyst, después de implementar la función en la consola en este paso.
  • listofitems_2 : Esta acción inicia una solicitud de API y activa un método GET en el módulo CRM personalizado EcomProducts, recuperando el nombre del producto, ID del producto, URL de la imagen del producto, precio y cantidad en stock.

  • placeanorder_4 : Esta acción acepta el ID del producto como entrada del usuario. Luego verifica la disponibilidad de stock del producto en particular en el módulo CRM EcomProducts. Si el stock está disponible, el bot procede a pedir la dirección de correo electrónico del usuario, la fecha esperada de entrega y la dirección de entrega. Una vez que se ingresan estos detalles, el bot realiza un pedido iniciando una solicitud de API y activando un método POST en el módulo CRM personalizado Orders. Se informará al usuario sobre la colocación exitosa del pedido a través del chatbot. Si el stock del producto no está disponible, se informará lo mismo al usuario.

  • vieworderdetails_3 : Esta acción activa la API de búsqueda de Zoho CRM para realizar una operación de búsqueda en el módulo personalizado Orders. El nombre del cliente, número de contacto, ID de correo electrónico, nombre del producto, precio del producto, URL de la imagen del producto, fecha esperada de entrega, dirección de entrega y estado del pedido se obtienen como respuesta.

  • changedeliveryaddress : Esta acción acepta el ID de correo electrónico asociado con el pedido, el ID del pedido y la dirección a la que se debe entregar el pedido, como entradas. Se activa la API de búsqueda de Zoho CRM en nuestro módulo personalizado Orders. Se validan el ID de correo electrónico y el ID del pedido dados y la nueva dirección se actualiza en el pedido ejecutando un método PUT en el módulo personalizado Orders.

  • rescheduleorderdate : Esta acción acepta el ID de correo electrónico asociado con el pedido y el ID del pedido como entradas. Se activa la API de búsqueda de Zoho CRM en nuestro módulo personalizado Orders, se realiza la operación de búsqueda para el ID del pedido dado. Se validan el ID de correo electrónico y el ID del pedido y la próxima fecha posible se actualiza como la fecha de entrega en el pedido nuevamente ejecutando un método PUT en el módulo personalizado Orders.

Los nombres de acción mencionados anteriormente son espacios de nombres de la acción creada en la consola. Asegúrate de actualizar los espacios de nombres generados para tus acciones en el código en las líneas 82, 145, 238, 337, 407 para los casos de switch listofitems_2, vieworderdetails, placeanorder, changedeliveryaddress, rescheduleordertolaterdate respectivamente.

Puedes obtener los espacios de nombres de la acción desde la consola como se muestra en la captura de pantalla a continuación.

copy-namespace

  1. welcome.js: En este archivo, hemos configurado el mensaje que se mostrará para saludar al usuario al iniciar una nueva conversación con el usuario.

  2. Fallback.js: En este archivo, hemos configurado el mensaje que se mostrará al usuario cuando el bot no pueda comprender el mensaje del usuario. En este caso, esta respuesta se mostrará en la conversación hasta que el usuario ingrese la respuesta válida y el bot la entienda.

  3. failure.js: En este archivo, hemos configurado el mensaje que se mostrará al usuario cuando ocurra una excepción al ejecutar la lógica empresarial.

  4. index.js: Este es el punto de entrada de la función y aquí mapearemos los archivos handler correspondientes como execute, welcome, fallback o failure según el todo prompt durante la conversación del bot.

Última actualización 2026-03-24 17:38:39 +0530 IST

ENLACES RELACIONADOS

Project Directory Structure