Implementación de Hooks
Implementación de Hooks
“Todos los caminos conducen a Roma” Es un célebre dicho que puede hacer alusión a un sinnúmero de situaciones y procesos tanto en nuestra vida personal como laboral. Pues existen muchas formas de llegar a un resultado, utilizando un procedimiento distinto.
Llevemos esto a una situación cotidiana. Imaginemos que existen 10 personas que tienen un almacén/bazar/tienda. Cada uno de estos negocios tienen rubros distintos (pero no dejan de ser una tienda). Todas poseen distintas obligaciones, y cada dueño tiene una manera de gestionar sus ventas y finanzas en general. Supongamos que buscamos proporcionarles una solución integral para gestionar sus ventas, ¿Qué es más fácil? ¿Qué cada una de estas empresas se adapte a nuestro producto, o nosotros adaptarnos a sus necesidades? Más aún: ¿Qué ocurre si a futuro, el usuario busca integrar los datos o funcionalidades de nuestro producto con otro sistema para otros propósitos?
Haciendo el nexo del caso anterior con la frase del comienzo. Todos buscan vender, gestionar sus ventas y cumplir con la normativa vigente.
Todo esto está bien para una tienda, pero escalemos a una solución más contundente en un rubro mucho más complejo.
El almacenamiento y manejo de productos sensibles es un caso parecido (sólo en relación con la frase del comienzo), pero a la vez distinto, pues todas deben cumplir con las normativas del Instituto de Salud pública (o entidades afines dependiendo del país) para poder operar, quienes deben hacer cumplir un control exigente sobre los productos que se manejan en este rubro, sin dejar de lado las fechas de vencimiento, bodegaje (almacenamiento caótico y no caótico) y administración de su inventario en general. Es imprescindible que las empresas del rubro cuenten con un sistema de trazabilidad tolerante a cambios e integración. Si te lo preguntas, sí, Optimiza WDP está preparado para este tipo de escenarios, y uno de los elementos más importantes para conseguir este propósito, es la utilización de hooks.
Entonces ¿Dónde entran en el juego los Hooks?
Podríamos definir un Hook, como un sistema de “Acción y Reacción”, el cual, al detectar un evento, éste reacciona ejecutando una tarea o acción. Esto es muy beneficioso para múltiples propósitos, como, por ejemplo:
– Mantener sistemas de trazabilidad fidedignos
– Permitir a los clientes del mismo rubro, tener distintas funcionalidades personalizadas y a la medida de su modelo de negocio.
– Permitir la integración con sistemas de terceros, o ERP’s
Una de las características de OPTIMIZA WDP, es su maleabilidad. Siendo capaz de modelar los variados flujos de trabajo que pueden existir en los laboratorios, farmacias o rubros afines.
Optimiza y los ERP’s
Un ERP (por sus siglas en inglés: Enterprise Resource Planning) es un sistema capaz de manejar las operaciones de las empresas desde el punto de vista financiero, facilitando la interconexión de los distintos procesos (aislados en muchos casos). Un ERP sirve para gestionar ventas, pagos, recursos humanos, logística, producción, etc. Son muy usados en medianas y grandes empresas, por lo que un software SaaS (Software as a service) debe estar preparado para la integración con este tipo de sistemas independiente del proveedor (SAP, Softland, Defontana, por mencionar algunos).
Integrando las partes
En un sistema robusto, es imprescindible el manejo de todo tipo de errores, tanto de lado del servidor, como de lado del cliente. Cuando trabajamos con integración de sistemas externos, esta tarea se complica, ya que no sólo dependemos de lo que realicemos de nuestro lado, sino que también juega un papel preponderante el sistema con el que buscamos integrarnos. Por nuestra parte, debemos tener controlado, que por alguna razón no exista un hook para dicho cliente (haya sido eliminado o editado) y para esto, utilizamos una de las tantas bondades que nos brinda NodeJS, (gracias a su asincronía) la capacidad de escuchar cambios en un fichero o carpeta dentro de nuestro proyecto.
var clientList = result.payload
for (let i = 0; i < clientList.length; i++) {
let curClient = clientList[i]
let cId = curClient.company_id
logger.info('Checking hooks for ' + cId)
let scriptFilename = setup.client_scripts + '/' + cId + '/' + entityHookScriptFile
let clientScript = null
try {
clientScript = require(scriptFilename)
clientHooks[cId] = clientScript
logger.info('Hooks found for ' + cId)
} catch (exception) {
clientHooks[cId] = null
logger.error(scriptFilename + '.js not found')
}
logger.info('Monitoring hooks script file ' + scriptFilename + '.js')
try {
fileClientLink[scriptFilename] = cId
let md5Previous = null
let fsWait = true
fs.watch(scriptFilename + '.js', (event, filename) => {
if (filename && event === 'rename') {
// Discard lib when it's renamed
var theInvolvedClient = fileClientLink[scriptFilename]
var theModuleName = require.resolve(scriptFilename)
delete require.cache[theModuleName]
clientHooks[theInvolvedClient] = null
logger.info('Hooks discarded for ' + cId)
return
}
if (filename && (event === 'change')) {
// Debounce.
if (fsWait) {
setTimeout(() => {
fsWait = false
}, 100)
return
}
// Make sure there is a change.
var md5Current = 0
try {
md5Current = md5(fs.readFileSync(scriptFilename + '.js'))
} catch (exception) {
console.log(exception)
}
if (md5Current === md5Previous) {
return
}
md5Previous = md5Current
logger.info('Change detected in hooks script file ' + scriptFilename + '.js')
var involvedClient = fileClientLink[scriptFilename]
try {
var moduleName = require.resolve(scriptFilename)
delete require.cache[moduleName]
clientHooks[involvedClient] = require(scriptFilename)
logger.info('Hooks reloaded for ' + cId)
} catch (exception) {
console.log(exception)
clientHooks[cId] = null
logger.error(scriptFilename + '.js invalid')
}
fsWait = true
}
})
} catch (exception) {
logger.error('Cannot establish monitor for ' + scriptFilename)
}
}
En síntesis, en el fragmento de código anterior, nos situamos en el interior de un ciclo, el cual se encarga de iterar todos los clientes y sus respectivos hooks. Una vez que nos aseguramos de que el hook exista; dejamos corriendo el monitor, el cual detectará si hay cambios de nombres, o cambios netamente internos. (Una forma de asegurarnos que sean cambios reales es asociando un cifrado MD5 al archivo que estamos observando para obtener un cifrado distinto cada vez que se registre un nuevo cambio).
Con nuestro sistema de hooks tenemos una serie de ventajas a la hora de implementar nuevas funcionalidades al sistema. Supongamos que algún cliente en específico desea recibir una notificación de correo electrónico cuando se realice algún movimiento. Sólo tendríamos que crear un script capaz de enviar un correo electrónico y lanzarlo cada vez que se haga una transacción de inventario.
Para efectos lúdicos y demostrativos, utilizando el sistema de hooks, se creó un fragmento que se conecta con la herramienta de trabajo en equipo “Slack” y notifica a través de su chat cada vez que se ha aprobado un proveedor para comenzar a trabajar con él. Convengamos que una integración con slack, además de ser lúdica, puede ser muy útil como mecanismo de notificación en línea para ciertos eventos.
var Slack = require('slack-node')
const webhookUri = 'https://hooks.slack.com/services//'
exports.hook_PROV_APPROVE = function (provider, files) {
console.log('hook_PROV_APPROVE ***')
console.log(provider)
console.log(files)
var slack = new Slack()
slack.setWebhook(webhookUri)
var msg = 'Proveedor ' + provider.code + ' aprobado.'
// Sending message
slack.webhook({
channel: '#general',
username: 'ftrac',
icon_emoji: ':robot_face:',
text: msg
}, function (err, response) {
if (err) {
console.log('Error: ' + response.statusCode)
}
console.log(response)
})
console.log('Fin ***')
}
Así como con Slack, es inmensa la cantidad de servicios con los cuales podríamos interactuar, sean públicos o privados. Por todo esto, queda claro el enorme poder que poseen los hooks. El límite está en el uso que quieras darles.