UNPKG

bot-functions

Version:
1,311 lines (1,231 loc) 53.2 kB
require('dotenv').config(); const os = require('os'); const fs = require('fs'); const axios = require('axios'); const FormData = require('form-data'); const concat = require("concat-stream"); const glob = require("glob"); const AdmZip = require('adm-zip'); const log = require('lambda-log'); const moment = require('moment'); const imaps = require('imap-simple'); const _ = require('lodash'); const { simpleParser } = require('mailparser'); const xpath = require('xpath'); const { JSDOM } = require('jsdom'); async function obtenerCorreos(email, password, subject) { const config = { imap: { user: email, password: password, host: 'imap.gmail.com', // Cambia esto si no estás usando Gmail port: 993, tls: true, tlsOptions: { rejectUnauthorized: false }, // Permitir certificados autofirmados authTimeout: 3000 } }; try { log.info("==> Conexion a Correos"); const connection = await imaps.connect(config); await connection.openBox('INBOX'); const searchCriteria = ['UNSEEN']; const fetchOptions = { bodies: ['HEADER', 'TEXT', ''], struct: true, markSeen: false, limit: 5 }; log.info("==> Busqueda de correos"); const messages = await connection.search(searchCriteria, fetchOptions); log.info("Exito al conectar"); const latestMessage = messages[messages.length - 1]; const parts = latestMessage.parts.filter(part => part.which === 'TEXT' || part.which === ''); const allParts = parts.map(part => part.body).join(''); const parsed = await simpleParser(allParts); let cleanText = parsed.text ? parsed.text.replace(/\n/g, '') : ''; const keywords = ['client', 'Please', 'access', 'rights', 'either', 'owners', 'podido', 'prueba', 'dentro', 'enlace', 'google', 'enviar', 'accept']; const regex = new RegExp(keywords.join('|'), 'gi'); cleanText = cleanText.replace(regex, ''); const codeMatches = cleanText.match(/\b\w{6}\b/g); const codes = codeMatches ? codeMatches : []; const parsedMessage = { from: parsed.from ? parsed.from.text : '', subject: parsed.subject || '', date: parsed.date || '', text: cleanText, html: parsed.html || '', codes: codes }; if (subject == parsedMessage.subject) { log.info("==> Se elimina el correo"); await connection.addFlags(latestMessage.attributes.uid, '\\Deleted'); await connection.closeBox(true); await connection.end(); return parsedMessage; } return [''] } catch (err) { console.error('Error al obtener el correo:', err); } } async function obtenerCodigo(subject) { const codes = await axios.post(`${process.env.API_CORREOS}`, { subject }); log.info(codes.data); return codes.data; } async function obtenerCodigoNuevo(subject) { const codes = await axios.post(`${process.env.API_NEW_CORREOS}`, { subject }); log.info(codes.data); return codes.data; } class EmailManager { constructor() { this.connection = null; } async connectEmail(config) { const emailConfig = { imap: { user: config.mail, password: config.pass, host: config.host, port: config.port, tls: config.tls, tlsOptions: { rejectUnauthorized: config.tlsOptions.rejectUnauthorized }, authTimeout: 10000 } }; try { this.connection = await imaps.connect(emailConfig); await this.connection.openBox('INBOX'); log.info("Successfully connected to email account"); return { success: true, message: 'Connected successfully' }; } catch (error) { log.error("Error connecting to email:", error); throw new Error(`Failed to connect to email: ${error.message}`); } } extractTextWithXPath(htmlContent, xpathExpression) { if (!htmlContent || !xpathExpression) { log.warn("HTML content or XPath expression missing"); return []; } try { const dom = new JSDOM(htmlContent); const document = dom.window.document; const extractedTexts = new Set(); const xpathResult = document.evaluate( xpathExpression, document, null, dom.window.XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null ); for (let i = 0; i < xpathResult.snapshotLength; i++) { const node = xpathResult.snapshotItem(i); this._addNodeContent(extractedTexts, node); } if (extractedTexts.size === 0) { try { const nodes = xpath.select(xpathExpression, document); this._processNodeList(extractedTexts, nodes); } catch (selectError) { this._tryCssFallback(extractedTexts, xpathExpression, document); } } return Array.from(extractedTexts).filter(text => text.trim().length > 0); } catch (error) { log.error("XPath extraction failed completely:", error); return []; } } _addNodeContent(collection, node) { if (!node) return; let content = ''; switch (node.nodeType) { case 1: content = node.textContent?.trim(); break; case 2: content = node.value?.trim(); break; case 3: content = node.data?.trim(); break; } if (content) collection.add(content); } _processNodeList(collection, nodes) { if (Array.isArray(nodes)) { nodes.forEach(node => this._addNodeContent(collection, node)); } else if (nodes) { if (typeof nodes === 'string') { collection.add(nodes.trim()); } else { this._addNodeContent(collection, nodes); } } } _tryCssFallback(collection, xpathExpression, document) { try { const cssSelector = this._xpathToCssSelector(xpathExpression); if (!cssSelector) return; document.querySelectorAll(cssSelector).forEach(element => { const text = element.textContent?.trim(); if (text) collection.add(text); }); } catch (cssError) { log.debug("CSS fallback also failed:", cssError); } } _xpathToCssSelector(xpath) { if (!xpath || typeof xpath !== 'string') return null; const conversions = [ { pattern: /^\/\/(\w+)$/, replacement: '$1' }, { pattern: /^\/\/(\w+)\[@class="([^"]+)"\]$/, replacement: '$1.$2' }, { pattern: /^\/\/(\w+)\[@id="([^"]+)"\]$/, replacement: '$1#$2' }, { pattern: /^\/\/\*\[@class="([^"]+)"\]$/, replacement: '.$1' }, { pattern: /^\/\/(\w+)\/text\(\)$/, replacement: '$1' } ]; for (const conv of conversions) { if (conv.pattern.test(xpath)) { return xpath.replace(conv.pattern, conv.replacement); } } try { let css = xpath.replace(/\/\//g, '/').replace(/^\//, ''); const parts = css.split('/').filter(p => p && p.trim().length); const mapped = parts.map(part => { part = part.replace(/\[@id=['"]([^'"]+)['"]\]/, '#$1'); part = part.replace(/\[@class=['"]([^'"]+)['"]\]/, (_, cls) => '.' + cls.trim().split(/\s+/).join('.')); part = part.replace(/\[@(\w+)=['"]([^'"]+)['"]\]/, '[$1="$2"]'); part = part.replace(/\/?text\(\)/g, ''); return part.trim(); }).filter(Boolean); const selector = mapped.join(' '); return selector || null; } catch (e) { return null; } } _buildOrFromEmails(emails) { if (emails.length === 1) { return ['FROM', emails[0]]; } return emails.reduce((acc, email) => { if (!acc) return ['FROM', email]; return ['OR', acc, ['FROM', email]]; }, null); } async searchEmails(searchOptions = {}) { if (!this.connection) { throw new Error('Not connected to email account.'); } const { subject, fromEmail, unreadOnly } = searchOptions; log.info("searchEmails criteria", { subject, fromEmail, unreadOnly }); try { const searchCriteria = []; if (unreadOnly) searchCriteria.push('UNSEEN'); if (subject) searchCriteria.push(['SUBJECT', subject]); const fromEmails = fromEmail.split(';').map(s => s.trim()); searchCriteria.push(this._buildOrFromEmails(fromEmails)); const sinceDate = new Date(Date.now() - 2 * 60 * 1000); searchCriteria.push(['SINCE', sinceDate]); const fetchOptions = { bodies: ['HEADER', 'TEXT', ''], struct: true, markSeen: false }; const messages = await this.connection.search(searchCriteria, fetchOptions); log.info(`Found ${messages.length} matching emails before limiting`); let limitedMessages = messages; try { limitedMessages = [...messages] .sort((a, b) => { const ad = new Date(a?.attributes?.date || 0).getTime(); const bd = new Date(b?.attributes?.date || 0).getTime(); if (ad && bd) return ad - bd; return (a?.attributes?.uid || 0) - (b?.attributes?.uid || 0); }); limitedMessages = limitedMessages.slice(-1); } catch (e) { log.warn("Failed to sort/limit messages, proceeding with all", { error: e.message }); } log.info(`Processing ${limitedMessages.length} email(s) after limiting`); const parsedMessages = []; for (const message of limitedMessages) { try { const headerPart = message.parts.find(part => part.which === 'HEADER'); const rawMessage = message.parts.find(part => part.which === ''); const headers = headerPart?.body || {}; let htmlContent = ''; let textContent = ''; if (rawMessage?.body) { try { const parsed = await simpleParser(rawMessage.body); htmlContent = parsed.html || ''; } catch (parseError) { log.error('Error parsing raw message:', parseError); } } const parsedMessage = { uid: message.attributes.uid, from: headers.from ? headers.from[0] : '', subject: headers.subject ? headers.subject[0] : '', html: htmlContent, text: textContent, date: headers.date ? headers.date[0] : '', flags: message.attributes.flags || [] }; parsedMessages.push(parsedMessage); } catch (error) { log.error('Error processing message:', error); } } return parsedMessages; } catch (error) { log.error("Error searching emails:", error); throw new Error(`Failed to search emails: ${error.message}`); } } async searchAndExtract(searchOptions) { const emails = await this.searchEmails(searchOptions); const results = []; for (const email of emails) { let extractedData = []; if (email.html) { log.info("Extracting from HTML content"); extractedData = this.extractTextWithXPath(email.html, searchOptions.xpathExpression); } results.push({ ...email, extractedData }); } return results; } async deleteEmails(uids) { if (!this.connection) { throw new Error('Not connected to email account'); } const uidArray = Array.isArray(uids) ? uids : [uids]; try { for (const uid of uidArray) { await this.connection.addFlags(uid, '\\Deleted'); } await this.connection.imap.expunge(); log.info(`Successfully deleted ${uidArray.length} email(s)`); return { success: true, deletedCount: uidArray.length, action: 'deleted' }; } catch (error) { log.error("Error deleting emails:", error); throw new Error(`Failed to delete emails: ${error.message}`); } finally { if (this.connection) { try { await this.connection.end(); this.connection = null; } catch (error) { log.error("Error disconnecting:", error); } } } } } async function manageEmails(config, searchOptions) { const emailManager = new EmailManager(); try { await emailManager.connectEmail(config); let results; if (!searchOptions.xpathExpression) { throw new Error("xpathExpression is mandatory"); } results = await emailManager.searchAndExtract(searchOptions); results.forEach( async (email) => { await emailManager.deleteEmails(email.uid); }); return { success: true, emails: results }; } catch (error) { log.error("Error in manageEmails:", error); return { success: false, error: error.message, emails: [] }; } } let separador = (os.type() === "Windows_NT") ? `\\` : "/"; async function* asyncGenerator(final) { var i = 0; while (i < final) { yield i++; } } const waitNtype = async (page, selector, text, timeout = 60000, visible = true) => { return new Promise(async function (resolve) { try { await sleep(1000); await page.waitForSelector(selector, { timeout: timeout, visible: visible }); await page.type(selector, text); await sleep(3000); resolve(0); } catch (e4) { resolve(1) } }); } const waitNclick = async (page, selector, timeout = 60000, visible = true) => { return new Promise(async function (resolve) { try { await sleep(1000); await page.waitForSelector(selector, { timeout: timeout, visible: visible }); await (await page.$$(selector))[0].click().then(x => resolve(0)); } catch (e4) { resolve(1) } }); } const pupp_findSelector = async (page, selector, time = 60000, visible = true) => { return new Promise(async function (resolve) { try { await page.waitForSelector(selector, { timeout: time, visible: visible }).then(function () { resolve(true); }); } catch (e1) { resolve(false); } }); }; const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs)); const waitFile = async (file, time = 500) => { return new Promise(async function (resolve) { let inc = 0; let found = []; while (!found.length && inc <= time) { glob(file, function (err, files) { if (err) { log.error(err.message) } else { found = files; } }); await sleep(1000); inc++; } if (found) { log.info(`file available after ${inc} seconds`); resolve(found[0]) } else { log.error(`Time exceeded`); resolve(false) } }); } const rename = async (inName, outName, ext) => { fs.rename(inName + ext, outName + ext, function (err) { if (err) log.error(err); }); }; const insertEvidence = async (rutaFile, rutaImg, db, idgfc, periodo, fecha, tipo) => { return new Promise(async function (resolve) { const strFile = (rutaFile != "") ? "rutaArchivo" : "rutaCaptura"; const fileInsert = (rutaFile != "") ? process.env.DO_PATH + rutaFile : process.env.DO_PATH + rutaImg; const regs = await axios.post(process.env.HAS_EVIDENCE_PATH, { db, idgfc, periodo, fecha }); if (regs.data.data) { await axios.post(process.env.UPDATE_EVIDENCE_PATH, { db, strFile, tipo, fileInsert, idgfc, periodo, fecha }); resolve(true); } else { await axios.post(process.env.INSERT_EVIDENCE_PATH, { db, strFile, tipo, fileInsert, idgfc, periodo, fecha }); resolve(true); } }) } const insertEvidence2 = async (rutaFile, rutaImg, db, idgfc, periodo, fecha, tipo) => { return new Promise(async function (resolve) { const strFile = (rutaFile != "") ? "rutaArchivo" : "rutaCaptura"; const fileInsert = (rutaFile != "") ? process.env.DO_PATH + rutaFile : process.env.DO_PATH + rutaImg; const regs = await axios.post(process.env.HAS_EVIDENCE_PATH2, { db, idgfc, periodo, fecha }); if (regs.data.data) { await axios.post(process.env.UPDATE_EVIDENCE_PATH2, { db, strFile, tipo, fileInsert, idgfc, periodo, fecha }); resolve(true); } else { await axios.post(process.env.INSERT_EVIDENCE_PATH2, { db, strFile, tipo, fileInsert, idgfc, periodo, fecha }); resolve(true); } }) } const insertEvidence3 = async (rutaFile, rutaImg, db, idgfc, periodo, fecha, tipo) => { return new Promise(async function (resolve) { const strFile = (rutaFile != "") ? "rutaArchivo" : "rutaCaptura"; const fileInsert = (rutaFile != "") ? rutaFile : rutaImg; const regs = await axios.post(process.env.HAS_EVIDENCE_PATH, { db, idgfc, periodo, fecha }); if (regs.data.data) { await axios.post(process.env.UPDATE_EVIDENCE_PATH, { db, strFile, tipo, fileInsert, idgfc, periodo, fecha }); resolve(true); } else { await axios.post(process.env.INSERT_EVIDENCE_PATH, { db, strFile, tipo, fileInsert, idgfc, periodo, fecha }); resolve(true); } }) } const insertEvidence4 = async (rutaFile, rutaImg, db, idgfc, periodo, fecha, tipo) => { return new Promise(async function (resolve) { const strFile = (rutaFile != "") ? "rutaArchivo" : "rutaCaptura"; const fileInsert = (rutaFile != "") ? rutaFile : rutaImg; const regs = await axios.post(process.env.HAS_EVIDENCE_PATH2, { db, idgfc, periodo, fecha }); if (regs.data.data) { await axios.post(process.env.UPDATE_EVIDENCE_PATH2, { db, strFile, tipo, fileInsert, idgfc, periodo, fecha }); resolve(true); } else { await axios.post(process.env.INSERT_EVIDENCE_PATH2, { db, strFile, tipo, fileInsert, idgfc, periodo, fecha }); resolve(true); } }) } const insertLog = async (params, codigo) => { return new Promise(async function (resolve) { try { if (params.reporte.period == 0) rutaLog = process.env.INSERT_LOG_PATH2; else rutaLog = process.env.INSERT_LOG_PATH; const insertLogResponse = await axios.post(rutaLog, { codigo, params }); return resolve(insertLogResponse.data.data) } catch (e) { resolve(); } }); }; const insertLog2 = async (params, codigo) => { return new Promise(async function (resolve) { try { const insertLogResponse = await axios.post(process.env.INSERT_LOG_PATH2, { codigo, params }); return resolve(insertLogResponse.data.data) } catch (e) { resolve(); } }); }; const insertLogExec = async (params, datoActual, datoAnterior) => { return new Promise(async function (resolve) { try { const insertLogExecResponse = await axios.post(process.env.INSERT_LOG_EXEC, { datoActual, datoAnterior, params }); return resolve(insertLogExecResponse.data.data) } catch (e) { resolve(); } }); }; const checkData = async (params) => { return new Promise(async (resolve) => { try { actualFunction = "checkData"; let campoC; const campo = (['v', 't'].includes(params.reporte.type.toLowerCase())) ? "ventasUnidades" : "existenciasUnidades"; if (params.reporte.dateStr == "fecha") { campoC = params.reporte.date1; } else { campoC = params.reporte.yearWeekOrMonth; } const result = await axios.post(process.env.HAS_DATA_PATH, { campo, table: `${params.robot.baseHyperCube}.${params.reporte.store}`, idRobot: params.robot.idPC, field: params.reporte.dateStr, value: campoC }); const res = (parseInt(result.data.data) === 0 || result.data.data === null) ? 1 : 0; resolve(res); } catch (error) { log.error(error.message) throw new Error("No se pudo verificar existencia de información"); } }); } const checkData2 = async (params, tipo = '') => { return new Promise(async (resolve) => { try { actualFunction = "checkData2"; let campoC, nameTable; const campo = (['v', 't'].includes(params.reporte.type.toLowerCase())) ? "ventasUnidades" : "existenciasUnidades"; if (tipo === 'ohcal1') campoC = params.reporte.intervalB[2]; else if (tipo === 'ohcal2') campoC = params.reporte.intervalB[0]; else if (params.reporte.dateStr == "fecha") campoC = params.reporte.date1; else campoC = params.reporte.yearWeekOrMonth; switch (params.robot.cadena.toLowerCase()) { case 'walmart': nameTable = 'supercenter'; break; case 'walmart tp': nameTable = 'supercentertp'; break; default: nameTable = params.robot.cadena.replace(/\s+/g, '').toLowerCase() break; } if (params.robot.proyecto.toLowerCase() == 'spinmaster2') { switch (params.robot.cadena.toLowerCase()) { case 'soriana': nameTable = 'sorianahipermercado'; break; case 'soriana tp': nameTable = 'sorianahipermercadotp'; break; default: nameTable = params.robot.cadena.replace(/\s+/g, '').toLowerCase() break; } } if (params.robot.proyecto.toLowerCase() == 'hanes') { switch (params.robot.cadena.toLowerCase()) { case 'sears mf': nameTable = 'searsmf'; break; case 'sears uw': nameTable = 'searsuw'; break; case 'sears pt': nameTable = 'searspt'; break; case 'cityfresko d': nameTable = 'cityfreskod'; break; case 'cityfresko uw': nameTable = 'cityfreskouw'; break; case 'coppel uw': nameTable = 'coppeluw'; break; case 'coppel d': nameTable = 'coppeld'; break; case 'coppel n': nameTable = 'coppeln'; break; default: nameTable = params.robot.cadena.replace(/\s+/g, '').toLowerCase() break; } } const table = `concentrado${nameTable}`; const result = await axios.post(process.env.HAS_DATA_PATH2, { campo, table: `${params.robot.baseHyperCube}.${table}`, field: params.reporte.dateStr, value: campoC }); const res = (parseInt(result.data.data) === 0 || result.data.data === null) ? 1 : 0; resolve(res); } catch (error) { log.error(error.message) throw new Error("No se pudo verificar existencia de información"); } }); } function hour() { const dLog = new Date(); const hh = (dLog.getHours() < 10) ? "0" + dLog.getHours() : dLog.getHours(); const mm = (dLog.getMinutes() < 10) ? "0" + dLog.getMinutes() : dLog.getMinutes(); return hh + ":" + mm; } const getParams = async (ejecucion) => { return new Promise(async function (resolve, reject) { try { const sendParams = { "period": process.env.PERIODO, "date": process.env.DIA_SEMANA_MES, "type0": ejecucion, "urgent0": 0, "existFile0": "", "idPC": process.env.ID_PROYECTO_CADENA, "proyecto": process.env.NOMBRE_CLIENTE } log.info(sendParams); const paramsAPI = await axios.post(process.env.GET_PARAMS_PATH, sendParams); const params = paramsAPI.data.data; return resolve(params); } catch (e) { return reject(new Error(e.message)); } }) } const sendErrorMail = async (data) => { return new Promise(async function (resolve, reject) { try { const mailResponse = await axios.post(process.env.MAIL_FAILED_PATH, data); return resolve() } catch (e) { return reject(new Error(e.message)); } }); } const renameFile = async (pathDownloads, params) => { return new Promise(async (resolve, reject) => { actualFunction = "renameFile"; try { const file = `${pathDownloads}${separador}${process.env.NAME_FILE}${process.env.EXTENSION_FILE}`; const fileExist = await waitFile(file, 600); await sleep(5000); if (fileExist) { await rename(fileExist.replace(process.env.EXTENSION_FILE, ""), `${pathDownloads}/${params.reporte.filename}`, process.env.EXTENSION_FILE); await waitFile(`${pathDownloads}/${params.reporte.filename}${process.env.EXTENSION_FILE}`, 10); await sleep(5000); resolve(); } } catch (error) { await insertLog(params, 207); return reject(new Error(error.message)); } }); } const sendFile = async (pathDownloads, params) => { return new Promise(async function (resolve, reject) { actualFunction = "sendFile"; try { const zip = new AdmZip(); zip.addLocalFile(`${pathDownloads}/${params.reporte.filename}${process.env.EXTENSION_FILE}`); zip.writeZip(`${pathDownloads}/${params.reporte.filename}.zip`); await sleep(5000); let formData = new FormData(); formData.append("upload", fs.createReadStream(`${pathDownloads}/${params.reporte.filename}.zip`)); const regs = await axios.post(process.env.AUTH_PATH, { email: process.env.EMAIL_API }); let headers = formData.getHeaders(); headers["Authorization"] = regs.data.data; headers["bucket"] = params.reporte.pathDOcean; const uploadFileResponse = await axios.post(process.env.UPLOAD_DO_PATH, formData, { headers }) if (uploadFileResponse.status === 200) { await insertEvidence(`${params.reporte.pathDOcean}/${params.reporte.filename}.zip`, "", params.robot.baseHyperCube, params.robot.idgfc, process.env.PERIODO, params.reporte.prefix, params.reporte.type) await insertLog(params, 305); resolve(); } } catch (error) { await insertLog(params, 108); return reject(new Error(error.message)); } }); } const sendFile2 = async (pathDownloads, params) => { return new Promise(async function (resolve, reject) { actualFunction = "sendFile2"; try { const zip = new AdmZip(); zip.addLocalFile(`${pathDownloads}/${params.reporte.filename}${process.env.EXTENSION_FILE}`); zip.writeZip(`${pathDownloads}/${params.reporte.filename}.zip`); await sleep(5000); let formData = new FormData(); formData.append("upload", fs.createReadStream(`${pathDownloads}/${params.reporte.filename}.zip`)); const regs = await axios.post(process.env.AUTH_PATH, { email: process.env.EMAIL_API }); let headers = formData.getHeaders(); headers["Authorization"] = regs.data.data; headers["bucket"] = params.reporte.pathDOcean; const uploadFileResponse = await axios.post(process.env.UPLOAD_DO_PATH, formData, { headers }) if (uploadFileResponse.status === 200) { await insertEvidence2(`${params.reporte.pathDOcean}/${params.reporte.filename}.zip`, "", params.robot.baseHyperCube, params.robot.idgfc, process.env.PERIODO, params.reporte.prefix, params.reporte.type) await insertLog2(params, 305); resolve(); } } catch (error) { await insertLog2(params, 108); return reject(new Error(error.message)); } }); } const sendImage = async (pathDownloads, params) => { return new Promise(async function (resolve, reject) { actualFunction = "sendImage"; try { let formData = new FormData(); formData.append("upload", fs.createReadStream(`${pathDownloads}/${params.reporte.filename}${process.env.EXTENSION_IMG}`)); formData.pipe(concat(async (data) => { const regs = await axios.post(process.env.AUTH_PATH, { email: process.env.EMAIL_API }); let headers = formData.getHeaders(); headers["Authorization"] = regs.data.data; headers["bucket"] = params.reporte.pathDOcean; const uploadFileResponse = await axios.post(process.env.UPLOAD_DO_PATH, data, { headers }) if (uploadFileResponse.status === 200) { await insertEvidence('', `${params.reporte.pathDOcean}/${params.reporte.filename}${process.env.EXTENSION_IMG}`, params.robot.baseHyperCube, params.robot.idgfc, process.env.PERIODO, params.reporte.prefix, params.reporte.type) await insertLog(params, 305); resolve(); } })) } catch (error) { await insertLog(params, 108); return reject(new Error(error.message)); } }); } const sendImage2 = async (pathDownloads, params) => { return new Promise(async function (resolve, reject) { actualFunction = "sendImage2"; try { let formData = new FormData(); formData.append("upload", fs.createReadStream(`${pathDownloads}/${params.reporte.filename}${process.env.EXTENSION_IMG}`)); formData.pipe(concat(async (data) => { const regs = await axios.post(process.env.AUTH_PATH, { email: process.env.EMAIL_API }); let headers = formData.getHeaders(); headers["Authorization"] = regs.data.data; headers["bucket"] = params.reporte.pathDOcean; const uploadFileResponse = await axios.post(process.env.UPLOAD_DO_PATH, data, { headers }) if (uploadFileResponse.status === 200) { await insertEvidence2('', `${params.reporte.pathDOcean}/${params.reporte.filename}${process.env.EXTENSION_IMG}`, params.robot.baseHyperCube, params.robot.idgfc, process.env.PERIODO, params.reporte.prefix, params.reporte.type) await insertLog2(params, 305); resolve(); } })) } catch (error) { await insertLog2(params, 108); return reject(new Error(error.message)); } }); } const sendData = async (params, dataJSON) => { return new Promise(async function (resolve, reject) { actualFunction = "sendData"; try { const batchPromises = []; const originalKeywork = params.reporte.keywork; const batchSize = Math.ceil(dataJSON.length / 5000); for await (let pos of asyncGenerator(batchSize)) { const batchData = dataJSON.slice((pos * 5000), (5000 * (pos + 1))); params.reporte.keywork = originalKeywork + pos; const response = await axios({ method: 'post', url: process.env.CREATE_PACKAGE_PATH, data: { params, dataJSON: batchData }, maxBodyLength: Infinity, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }); batchPromises.push(response.status) } batchPromises.map(reg => log.info('Insert status', reg)); if (batchPromises.every(reg => reg == 200)) { resolve({ status: "Packages inserted successfully", exit: 1 }); } else { return reject(new Error('No se insertaron todos los paquetes')); } } catch (error) { await insertLog(params, 107); return reject(new Error(error.message)); } }); } const sendData2 = async (params, dataJSON) => { return new Promise(async function (resolve, reject) { actualFunction = "sendData2"; try { const batchPromises = []; const originalKeywork = params.reporte.keywork; const batchSize = Math.ceil(dataJSON.length / 5000); for await (let pos of asyncGenerator(batchSize)) { const batchData = dataJSON.slice((pos * 5000), (5000 * (pos + 1))); params.reporte.keywork = originalKeywork + pos; const response = await axios({ method: 'post', url: process.env.CREATE_PACKAGE_PATH2, data: { params, dataJSON: batchData }, maxBodyLength: Infinity, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }); batchPromises.push(response.status) } batchPromises.map(reg => log.info('Insert status', reg)); if (batchPromises.every(reg => reg == 200)) { resolve({ status: "Packages inserted successfully", exit: 1 }); } else { return reject(new Error('No se insertaron todos los paquetes')); } } catch (error) { await insertLog(params, 107); return reject(new Error(error.message)); } }); } const sendDataCH = async (params, dataJSON) => { return new Promise(async function (resolve, reject) { actualFunction = "sendDataCH"; try { const batchPromises = []; const stringData = JSON.stringify(dataJSON); const response = await axios({ method: 'post', url: process.env.INSERT_CH, data: {jsonContent: stringData }, maxBodyLength: Infinity, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } }); batchPromises.push(response.status); batchPromises.map(reg => log.info('Insert status', reg)); if (batchPromises.every(reg => reg == 200)) { resolve({ status: "Packages inserted successfully", exit: 1 }); } else { return reject(new Error('No se insertaron todos los paquetes')); } } catch (error) { await insertLog(params, 107); return reject(new Error(error.message)); } }); } const waitFrame = (page, frame, framename, info, timeout, parent = null) => { return new Promise(async function (resolve, reject) { let counter = 0; while (!frame && counter < timeout) { frame = await page.frames().find(f => f.name() === framename && (parent ? f.parentFrame().name() == parent : true)); await sleep(1000); counter++; } if (frame) { resolve(frame); } else { return reject(new Error("Not frame (waitFrame)")); } }); } const waitlastWindow = async (browser, info, numws, pos) => { return new Promise(async function (resolve) { let len = 0; info.counter = 0; while (len != numws && info.counter < 30) { log.info("Waiting window changes ...") len = (await browser.pages()).length await sleep(1000); info.counter++; } const thispage = await (await browser.pages())[pos - 1] resolve(thispage) }) } const evalCom = async (info, casse, resp, com, type) => { if (info.current == casse) { if ((resp.expect ? resp.counterExp < resp.expect.length && Object.keys(resp.expect[resp.counterExp])[0] == type && resp.expect[resp.counterExp][type].includes(com.url()) : false)) { resp.counterExp++; if (resp.counterExp == resp.expect.length) { resp.step = true; } } else if ((resp.regexpp ? resp.counterReg < resp.regexpp.length && Object.keys(resp.regexpp[resp.counterReg])[0] == type && com.url().match(resp.regexpp[resp.counterReg][type]).length : false)) { resp.counterReg++; if (resp.counterReg == resp.regexpp.length) { resp.step = true; resp.record.push(com.url()); } } } } const leftPad = (number, targetLength) => { let output = number + ''; while (output.length < targetLength) { output = '0' + output; } return output; } const sumSalesInAPeriod = async (params, arrJSON) => { return new Promise(async function (resolve, reject) { try { let dataJson = {}; let keyArr = ''; let ventaU = 0; let ventaAntU = 0; let ventaP = 0; let ventaAntP = 0; arrJSON.forEach(e => { keyArr = `${e.cod}||${e.centro}`; if (!dataJson.hasOwnProperty(keyArr)) { dataJson[keyArr] = { proyecto: (params.robot.proyecto).toUpperCase(), gpocad: (params.robot.cadena).toUpperCase(), razonSocial: (params.robot.razonSocial).toUpperCase(), fecha: params.reporte.finalCY, tipoC: params.reporte.period, centro: e.centro, nomTienda: e.nomTienda, cod: e.cod, item: e.item, upc: e.upc, nomProd: e.nomProd, ventaU: e.ventaU, ventaP: e.ventaP } } else { ventaAntU = parseFloat(e.ventaU); ventaU = (ventaAntU + parseFloat(dataJson[keyArr].ventaU)); dataJson[keyArr].ventaU = ventaU; ventaAntP = parseFloat(e.ventaP); ventaP = (ventaAntP + parseFloat(dataJson[keyArr].ventaP)); dataJson[keyArr].ventaP = ventaP; } }); return resolve(Object.values(dataJson)); } catch (error) { console.error(error.message) throw new Error("Error en la función sumSalesInAPeriod"); } }); } const getStatus = async (db, cadena, fecha) => { return new Promise(async function (resolve, reject) { try { const status = await axios.get(`${process.env.GET_STATUS_PATH}${db}/${fecha}/${cadena.toLowerCase()}`); return resolve(status); } catch (e) { log.info(e); return reject(new Error(e.message)); } }) } const updateStatus = async (params, position, date) => { return new Promise(async function (resolve, reject) { try { await axios.post(process.env.SET_STATUS_PATH, { db: params.robot.baseHyperCube, position, cadena: params.robot.cadena.toLowerCase(), date }); return resolve(true); } catch (e) { return reject(new Error(e.message)); } }) } async function* asyncGenerator(final) { var i = 0; while (i < final) { yield i++; } } const getParamsAndStatus = async (ejecucion) => { actualFunction = "getParamsAndStatus"; const txtFecha = (process.env.DIA_SEMANA_MES == '' ? 'Sin Fecha' : 'Con Fecha'); let initialParams = await getParams(ejecucion); if(txtFecha == 'Sin Fecha' && process.env.ID_PROYECTO_CADENA == 1419){ const maxDate = await lastDateSales(initialParams); const nuevaFecha = moment(maxDate, "YYYYMMDD").add(8, 'days').format("YYYYMMDD"); process.env.DIA_SEMANA_MES = nuevaFecha; initialParams = await getParams(ejecucion); } const status = await getStatus(initialParams.robot.baseHyperCube, initialParams.robot.cadena.toLowerCase(), initialParams.reporte.date1.replace(/-/gi, '')); return { initialParams, status: status.data.status }; }; function reformatDate(date, inf, outf) { let d; switch (inf) { case "yyyy-MM-dd": d = { year: date.split('-')[0], month: date.split('-')[1], day: date.split('-')[2] } break; case "dd/MM/yyyy": d = { year: date.split('/')[2], month: date.split('/')[1], day: date.split('/')[0] } break; case "MM/dd/yyyy": d = { year: date.split('/')[2], month: date.split('/')[0], day: date.split('/')[1] } break; case "yyyyMMdd": d = { year: date.substr(0, 4), month: date.substr(4, 2), day: date.substr(6, 2) }; break; } switch (outf) { case "MM/dd/yyyy": return `${d.month}/${d.day}/${d.year}` case "dd/MM/yyyy": return `${d.day}/${d.month}/${d.year}` case "yyyy-MM-dd": return `${d.year}-${d.month}-${d.day}` case "MM.yyyy": return `${d.month}.${d.year}` case "MM-dd-yyyy": return `${d.month}-${d.day}-${d.year}` case "dd-MM-yyyy": return `${d.day}-${d.month}-${d.year}` } } const getIDReportSoriana = async (ejecucion) => { return new Promise(async function (resolve, reject) { try { const initialParams = await getParams(ejecucion); const idReport = await axios.get(`${process.env.GET_ID_REPORT_SORIANA}/${initialParams.robot.baseHyperCube}/${initialParams.reporte.finalCY}/${ejecucion}/${initialParams.reporte.period}`); return resolve(idReport.data.idReport); } catch (e) { return reject(new Error(e.message)); } }) } const setIDReportSoriana = async (params, idReport) => { return new Promise(async function (resolve, reject) { try { await axios.post(process.env.SET_ID_REPORT_SORIANA, { db: params.robot.baseHyperCube, date: params.reporte.finalCY, tipo: params.reporte.type, period: params.reporte.period, idReport }); return resolve(true); } catch (e) { return reject(new Error(e.message)); } }) } const updateIDReportSoriana = async (params, idReport) => { return new Promise(async function (resolve, reject) { try { await axios.post(process.env.SET_ID_REPORT_SORIANA, { db: params.robot.baseHyperCube, date: params.reporte.finalCY, tipo: params.reporte.type, period: params.reporte.period, idReport }); return resolve(true); } catch (e) { return reject(new Error(e.message)); } }) } const sendFile3 = async (pathDownloads, params) => { return new Promise(async function (resolve, reject) { actualFunction = "sendFile3"; try { const zip = new AdmZip(); zip.addLocalFile(`${pathDownloads}/${params.reporte.filename}${process.env.EXTENSION_FILE}`); zip.writeZip(`${pathDownloads}/${params.reporte.filename}.zip`); await sleep(5000); const key = params.reporte.pathS3 + '/' + params.reporte.filename + '.zip'; const fileData = fs.readFileSync(`${pathDownloads}/${params.reporte.filename}.zip`); const regs = await axios.post(process.env.AUTH_PATH, { email: process.env.EMAIL_API }); const body = { type: 1, bucketName: process.env.S3_BUCKET, file: fileData.toString('base64'), key }; const uploadFileResponse = await axios.post(process.env.S3_UPLOAD_FILE, body, { maxBodyLength: Infinity, headers: { 'Authorization': regs.data.data, 'Content-Type': 'application/json' } } ); if (uploadFileResponse.status === 200) { await insertEvidence3(uploadFileResponse.data.data, '', params.robot.baseHyperCube, params.robot.idgfc, process.env.PERIODO, params.reporte.prefix, params.reporte.type); await insertLog(params, 305); resolve(); } } catch (error) { await insertLog(params, 108); return reject(new Error(error.message)); } }); } const sendFile4 = async (pathDownloads, params) => { return new Promise(async function (resolve, reject) { actualFunction = "sendFile4"; try { const zip = new AdmZip(); let periodo, fecha; zip.addLocalFile(`${pathDownloads}/${params.reporte.filename}${process.env.EXTENSION_FILE}`); zip.writeZip(`${pathDownloads}/${params.reporte.filename}.zip`); await sleep(5000); const key = params.reporte.pathS3 + '/' + params.reporte.filename + '.zip'; const fileData = fs.readFileSync(`${pathDownloads}/${params.reporte.filename}.zip`); const regs = await axios.post(process.env.AUTH_PATH, { email: process.env.EMAIL_API }); const body = { type: 1, bucketName: process.env.S3_BUCKET, file: fileData.toString('base64'), key }; const uploadFileResponse = await axios.post(process.env.S3_UPLOAD_FILE, body, { maxBodyLength: Infinity, headers: { 'Authorization': regs.data.data, 'Content-Type': 'application/json' } } ); if (uploadFileResponse.status === 200) { periodo = process.env.PERIODO fecha = params.reporte.prefix; //CARGA DE EVIDENCIAS DE BOTS SEMANALES Y MENSUALES const gfcSemanal = [82,398,49495,49845,50119,39369,50045,50124,50114,50140,50137,50141,50157,50160,50159,50169,50170,50172,50182,50191,50192,50193,50187,50203]; if(gfcSemanal.includes(params.robot.idgfc)){ periodo = 0; fecha = params.reporte.interval[params.reporte.interval.length - 1]; } await insertEvidence4(uploadFileResponse.data.data, '', params.robot.baseHyperCube, params.robot.idgfc, periodo, fecha, params.reporte.type) await insertLog2(params, 305); resolve(); } } catch (error) { await insertLog2(params, 108); return reject(new Error(error.message)); } }); } const sendImage3 = async (pathDownloads, params) => { return new Promise(async function (resolve, reject) { actualFunction = "sendFile3"; try { const key = params.reporte.pathS3 + '/' + params.reporte.filename + process.env.EXTENSION_IMG; const fileData = fs.readFileSync(`${pathDownloads}/${params.reporte.filename}${process.env.EXTENSION_IMG}`); const regs = await axios.post(process.env.AUTH_PATH, { email: process.env.EMAIL_API }); const body = { type: 1, bucketName: process.env.S3_BUCKET, file: fileData.toString('base64'), key }; const uploadFileResponse = await axios.post(process.env.S3_UPLOAD_FILE, body, { maxBodyLength: Infinity, headers: { 'Authorization': regs.data.data, 'Content-Type': 'application/json' } } ); if (uploadFileResponse.status === 200) { await insertEvidence3('', uploadFileResponse.data.data, params.robot.baseHyperCube, params.robot.idgfc, process.env.PERIODO, params.reporte.prefix, params.reporte.type); await insertLog(params, 305); resolve(); } } catch (error) { await insertLog(params, 108); return reject(new Error(error.message)); } }); } const sendImage4 = async (pathDownloads, params) => { return new Promise(async function (resolve, reject) { actualFunction = "sendImage4"; try { const key = params.reporte.pathS3 + '/' + params.reporte.filename + process.env.EXTENSION_IMG; const fileData = fs.readFileSync(`${pathDownloads}/${params.reporte.filename}${process.env.EXTENSION_IMG}`); const regs = await axios.post(process.env.AUTH_PATH, { email: process.env.EMAIL_API }); const body = { type: 1, bucketName: process.env.S3_BUCKET, file: fileData.toString('base64'), key }; const uploadFileResponse = await axios.post(process.env.S3_UPLOAD_FILE, body, { maxBodyLength: Infinity, headers: { 'Authorization': regs.data.data, 'Content-Type': 'application/json' } } ); if (uploadFileResponse.status === 200) { await insertEvidence4('', uploadFileResponse.data.data, params.robot.baseHyperCube, params.robot.idgfc, process.env.PERIODO, params.reporte.prefix, params.reporte.type) await insertLog2(params, 305); resolve(); } } catch (error) { await insertLog2(params, 108); return reject(new Error(error.message)); } }); } const sendChunks = async (pathDownloads, params) => { return new Promise(async function (resolve, reject) { actualFunction = "sendChunks"; try { const zip = new AdmZip(); zip.addLocalFile(`${pathDownloads}/${params.reporte.filename}${process.env.EXTENSION_FILE}`); zip.writeZip(`${pathDownloads}/${params.reporte.filename}.zip`); await sleep(5000); const key = params.reporte.pathS3 + '/' + params.reporte.filename + '.zip'; const fileData = fs.readFileSync(`${pathDownloads}/${params.reporte.filename}.zip`); const regs = await axios.post(process.env.AUTH_PATH, { email: process.env.EMAIL_API }); let data = fileData.toString('base64'); const chunks = data.match(/.{1,5000000}/g); let numberChunk = 1; let uploadFileResponse for (let chunk of chunks) { const body = { type: 1, bucketName: process.env.S3_BUCKET, file: chunk, key, numberChunk, maxChunks: chunks.length }; uploadFileResponse = await axios.post(process.env.S3_CHUNKS_EVIDENCE, body, { maxBodyLength: Infinity, headers: { 'Authorization': regs.data.data, 'Content-Type': 'application/json' } } ); numberChunk++; } await insertEvidence3(uploadFileResponse.data.data, '', params.robot.baseHyperCube, params.robot.idgfc, process.env.PERIODO, params.reporte.prefix, params.reporte.type); await insertLog(params, 305); resolve(); } catch (error) { await insertLog(params, 108); return reject(new Error(error.message)); } }); } const sendDataDaily = (params, data) => { return new Promise(async (resolve, reject) => { try { const hasData = await checkData2(params); if (!hasData) { log.info('Ya cuenta con data diaria') return resolve(0); } actualFunction = "sendDailyData"; let dataDaily = await processDataDaily(params.reporte.interval, data); if (!dataDaily.length) { return resolve(0); }; await sendData2(params, dataDaily); return resolve(1); } catch (error) { log.info(error.message) await insertLog(params, 108); return reject(new Error(error.message)); } }); } const processDataDaily = (intervalDays, dataD) => { return new Promise(async (resolve, reject) => { try { resolve(dataD.map(d => { return { proyecto: d.proyecto, gpocad: d.gpocad, razonSocial: d.razonSocial, fecha: (intervalDays[intervalDays.length - 1]), tipoC: 0, centro: d.centro, nomTienda: d.nomTienda, upc: d.upc, cod: d.cod, item: d.item, nomProd: d.nomProd, ventaU: d.ventaU, ventaP: d.ventaP, invU: d.invU, invP: d.invP, pzasCaja: d.pzasCaja } })); } catch (error) { return reject(new Error(error.message)); } }); } const checkDataVI = async (params) => { return new Promise(async (resolve) => { try { actualFunction = "checkDataVI"; let campoC, nameTable; const campo = (['v', 't'].includes(params.reporte.type.toLowerCase())) ? "ventasUnidades" : "existenciasUnidades"; if (params.reporte.dateStr == "fecha") campoC = params.reporte.date1; else campoC = params.reporte.yearWeekOrMonth; nameTable = params.robot.cadena.replace(/\s+/g, '').toLowerCase() const table = `concentrado${nameTable}`; const result = await axios.post(