From 8f9afd5f232ed0415479fbd8e3b09cf47e7fe7ee Mon Sep 17 00:00:00 2001 From: adriano Date: Thu, 18 Jul 2024 21:41:03 -0300 Subject: [PATCH] fix: adjust API key handling and optimize call journaling --- .../hubspot_bearer_auth_editind_ticket.json | 188 ++++++++++++++++++ .../hubspot_bearer_auth_editing2.json | 188 ++++++++++++++++++ ... => pipedrive_api_token_auth_editing.json} | 25 +-- .../token_hubspot_tickets_scope.txt | 1 + backend/controllers/crmController.js | 18 +- backend/models/CRM.js | 2 +- backend/utils/createCRMContact.js | 2 +- backend/utils/createContact.js | 9 +- backend/utils/journaling.js | 4 +- backend/utils/lookupCRMContactByPhone.js | 18 ++ backend/utils/requestConfigHeader.js | 12 +- backend/utils/templateValidator.js | 2 +- frontend/src/components/UploadFile.js | 1 + 13 files changed, 439 insertions(+), 31 deletions(-) create mode 100644 backend/Templates-test/hubspot_bearer_auth_editind_ticket.json create mode 100644 backend/Templates-test/hubspot_bearer_auth_editing2.json rename backend/Templates-test/{pipedrive_bearer_auth_editing.json => pipedrive_api_token_auth_editing.json} (81%) create mode 100644 backend/Templates-test/token_hubspot_tickets_scope.txt diff --git a/backend/Templates-test/hubspot_bearer_auth_editind_ticket.json b/backend/Templates-test/hubspot_bearer_auth_editind_ticket.json new file mode 100644 index 0000000..0efc058 --- /dev/null +++ b/backend/Templates-test/hubspot_bearer_auth_editind_ticket.json @@ -0,0 +1,188 @@ +{ + "authentication":{ + "type": "bearer", + "token": "pat-na1-7aca13dd-9ba5-48db-bf35-570844d31abb", + "crmPhoneTest": "5511988334455" + }, + "crmRest":[ + { + "createContactRecord":{ + "request":{ + "requestContentType":"application/json", + "requestEncoding":"Json", + "requestType":"Post", + "responseType":"Json", + "url":"https://api.hubapi.com/contacts/v1/contact" + }, + "body":{ + "properties":[ + { + "property":"phone", + "value":"crmPhone" + } + ] + }, + "response":{ + "id":"vid" + } + } + }, + { + "lookupContactByPhone":{ + "request":{ + "requestContentType":"application/json", + "requestEncoding":"Json", + "requestType":"Get", + "responseType":"Json", + "url":"https://api.hubapi.com/contacts/v1/search/query?q=crmPhone" + }, + "response":{ + "phone":"contacts.properties.phone.value", + "id":"contacts.vid" + } + } + }, + { + "callJournaling":{ + "request":{ + "requestContentType":"application/json", + "requestEncoding":"Json", + "requestType":"Post", + "responseType":"Json", + "url":"https://api.hubapi.com/engagements/v1/engagements" + }, + "calls": [ + { + "inboundAnsweredCall": { + "engagement": { + "active": true, + "type": "CALL" + }, + "associations": { + "contactIds": [ + { + "_prop": "crmContactId", + "_type": "number" + } + ] + }, + "metadata": { + "toNumber": { + "_prop": "crmAgent", + "_type": "string" + }, + "fromNumber": { + "_prop": "crmPhone", + "_type": "string" + }, + "status": "COMPLETED", + "durationMilliseconds": { + "_prop": "crmCallDuration", + "_type": "number", + "_format": "milliseconds" + }, + "body": "Ligação recebida - inbound call", + "disposition": "f240bbac-87c9-4f6e-bf70-924b57d47db7" + } + } + }, + { + "inboundMissedCall": { + "engagement": { + "active": true, + "type": "CALL" + }, + "associations": { + "contactIds": [ + { + "_prop": "crmContactId", + "_type": "number" + } + ] + }, + "metadata": { + "toNumber": { + "_prop": "crmAgent", + "_type": "string" + }, + "fromNumber": { + "_prop": "crmPhone", + "_type": "string" + }, + "status": "COMPLETED", + "body": "Ligação perdida - inbound call", + "disposition": "f240bbac-87c9-4f6e-bf70-924b57d47db7" + } + } + }, + { + "outboundAnsweredCall": { + "engagement": { + "active": true, + "type": "CALL" + }, + "associations": { + "contactIds": [ + { + "_prop": "crmContactId", + "_type": "number" + } + ] + }, + "metadata": { + "fromNumber": { + "_prop": "crmPhone", + "_type": "string" + }, + "toNumber": { + "_prop": "crmAgent", + "_type": "string" + }, + "status": "COMPLETED", + "durationMilliseconds": { + "_prop": "crmCallDuration", + "_type": "number", + "_format": "milliseconds" + }, + "body": "Ligação atendida - outbound call", + "disposition": "f240bbac-87c9-4f6e-bf70-924b57d47db7" + } + } + }, + { + "outboundUnansweredCall": { + "engagement": { + "active": true, + "type": "CALL" + }, + "associations": { + "contactIds": [ + { + "_prop": "crmContactId", + "_type": "number" + } + ] + }, + "metadata": { + "fromNumber": { + "_prop": "crmAgent", + "_type": "string" + }, + "toNumber": { + "_prop": "crmPhone", + "_type": "string" + }, + "status": "COMPLETED", + "body": "Ligação perdida - oubound call", + "disposition": "f240bbac-87c9-4f6e-bf70-924b57d47db7" + } + } + } + ], + "response":{ + + } + } + } + ] +} \ No newline at end of file diff --git a/backend/Templates-test/hubspot_bearer_auth_editing2.json b/backend/Templates-test/hubspot_bearer_auth_editing2.json new file mode 100644 index 0000000..0efc058 --- /dev/null +++ b/backend/Templates-test/hubspot_bearer_auth_editing2.json @@ -0,0 +1,188 @@ +{ + "authentication":{ + "type": "bearer", + "token": "pat-na1-7aca13dd-9ba5-48db-bf35-570844d31abb", + "crmPhoneTest": "5511988334455" + }, + "crmRest":[ + { + "createContactRecord":{ + "request":{ + "requestContentType":"application/json", + "requestEncoding":"Json", + "requestType":"Post", + "responseType":"Json", + "url":"https://api.hubapi.com/contacts/v1/contact" + }, + "body":{ + "properties":[ + { + "property":"phone", + "value":"crmPhone" + } + ] + }, + "response":{ + "id":"vid" + } + } + }, + { + "lookupContactByPhone":{ + "request":{ + "requestContentType":"application/json", + "requestEncoding":"Json", + "requestType":"Get", + "responseType":"Json", + "url":"https://api.hubapi.com/contacts/v1/search/query?q=crmPhone" + }, + "response":{ + "phone":"contacts.properties.phone.value", + "id":"contacts.vid" + } + } + }, + { + "callJournaling":{ + "request":{ + "requestContentType":"application/json", + "requestEncoding":"Json", + "requestType":"Post", + "responseType":"Json", + "url":"https://api.hubapi.com/engagements/v1/engagements" + }, + "calls": [ + { + "inboundAnsweredCall": { + "engagement": { + "active": true, + "type": "CALL" + }, + "associations": { + "contactIds": [ + { + "_prop": "crmContactId", + "_type": "number" + } + ] + }, + "metadata": { + "toNumber": { + "_prop": "crmAgent", + "_type": "string" + }, + "fromNumber": { + "_prop": "crmPhone", + "_type": "string" + }, + "status": "COMPLETED", + "durationMilliseconds": { + "_prop": "crmCallDuration", + "_type": "number", + "_format": "milliseconds" + }, + "body": "Ligação recebida - inbound call", + "disposition": "f240bbac-87c9-4f6e-bf70-924b57d47db7" + } + } + }, + { + "inboundMissedCall": { + "engagement": { + "active": true, + "type": "CALL" + }, + "associations": { + "contactIds": [ + { + "_prop": "crmContactId", + "_type": "number" + } + ] + }, + "metadata": { + "toNumber": { + "_prop": "crmAgent", + "_type": "string" + }, + "fromNumber": { + "_prop": "crmPhone", + "_type": "string" + }, + "status": "COMPLETED", + "body": "Ligação perdida - inbound call", + "disposition": "f240bbac-87c9-4f6e-bf70-924b57d47db7" + } + } + }, + { + "outboundAnsweredCall": { + "engagement": { + "active": true, + "type": "CALL" + }, + "associations": { + "contactIds": [ + { + "_prop": "crmContactId", + "_type": "number" + } + ] + }, + "metadata": { + "fromNumber": { + "_prop": "crmPhone", + "_type": "string" + }, + "toNumber": { + "_prop": "crmAgent", + "_type": "string" + }, + "status": "COMPLETED", + "durationMilliseconds": { + "_prop": "crmCallDuration", + "_type": "number", + "_format": "milliseconds" + }, + "body": "Ligação atendida - outbound call", + "disposition": "f240bbac-87c9-4f6e-bf70-924b57d47db7" + } + } + }, + { + "outboundUnansweredCall": { + "engagement": { + "active": true, + "type": "CALL" + }, + "associations": { + "contactIds": [ + { + "_prop": "crmContactId", + "_type": "number" + } + ] + }, + "metadata": { + "fromNumber": { + "_prop": "crmAgent", + "_type": "string" + }, + "toNumber": { + "_prop": "crmPhone", + "_type": "string" + }, + "status": "COMPLETED", + "body": "Ligação perdida - oubound call", + "disposition": "f240bbac-87c9-4f6e-bf70-924b57d47db7" + } + } + } + ], + "response":{ + + } + } + } + ] +} \ No newline at end of file diff --git a/backend/Templates-test/pipedrive_bearer_auth_editing.json b/backend/Templates-test/pipedrive_api_token_auth_editing.json similarity index 81% rename from backend/Templates-test/pipedrive_bearer_auth_editing.json rename to backend/Templates-test/pipedrive_api_token_auth_editing.json index 33f4176..633630a 100644 --- a/backend/Templates-test/pipedrive_bearer_auth_editing.json +++ b/backend/Templates-test/pipedrive_api_token_auth_editing.json @@ -2,7 +2,7 @@ "authentication": { "type": "api_token", "token": "1c97c52596abc18d3f727df3a620b5ef3f4f7d29", - "crmPhoneTest": "5511988334455" + "crmPhoneTest": "5511988325936" }, "crmRest": [ { @@ -40,8 +40,8 @@ "url": "https://api.pipedrive.com/v1/persons/search?term=crmPhone" }, "response": { - "phone": "data.items.item.phones[0]", - "id": "data.item.id" + "phone": "data.items[0].item.phones[0]", + "id": "data.items[0].item.id" } } }, @@ -52,7 +52,7 @@ "requestEncoding": "Json", "requestType": "Post", "responseType": "Json", - "url": "https://api.hubapi.com/engagements/v1/engagements" + "url": "https://api.pipedrive.com/v1/activities" }, "calls": [ { @@ -61,8 +61,8 @@ "type": "Call", "person_id": "crmContactId", "done": "1", - "deal_id": "2", - "note": "Ligação recebida +crmPhone" + "due_date": "YYYY-MM-DD", + "due_time": "HH:MM" } }, { @@ -71,8 +71,8 @@ "type": "Call", "person_id": "crmContactId", "done": "0", - "deal_id": "2", - "note": "Ligação perdida +crmPhone" + "due_date": "YYYY-MM-DD", + "due_time": "HH:MM" } }, { @@ -81,8 +81,9 @@ "type": "Call", "person_id": "crmContactId", "done": "1", - "deal_id": "2", - "note": "Ligação realizada para +crmPhone" + "due_date": "YYYY-MM-DD", + "due_time": "HH:MM", + "note": "" } }, { @@ -91,8 +92,8 @@ "type": "Call", "person_id": "crmContactId", "done": "0", - "deal_id": "2", - "note": "Ligação realizada para +crmPhone" + "due_date": "YYYY-MM-DD", + "due_time": "HH:MM" } } ], diff --git a/backend/Templates-test/token_hubspot_tickets_scope.txt b/backend/Templates-test/token_hubspot_tickets_scope.txt new file mode 100644 index 0000000..974f56d --- /dev/null +++ b/backend/Templates-test/token_hubspot_tickets_scope.txt @@ -0,0 +1 @@ +pat-na1-37da6668-e0b1-44cb-bd2d-596f5f65634a \ No newline at end of file diff --git a/backend/controllers/crmController.js b/backend/controllers/crmController.js index 6ebb712..95aa462 100644 --- a/backend/controllers/crmController.js +++ b/backend/controllers/crmController.js @@ -60,20 +60,20 @@ const deleteCompany = async (req, res) => { const callJournaling = async (req, res) => { - const { companyId, operation, crmPhone, crmAgent, crmCallDuration } = req.body + const { companyId, operation, crmPhone, crmAgent, crmCallDuration, crmFirstName } = req.body mustContainProperties(req, ['companyId', 'operation', 'crmPhone', 'crmAgent',]) - if (operation == 'inboundAnsweredCall' && !crmCallDuration) - throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is inboundAnsweredCall`) - if (operation == 'outboundAsweredCall' && !crmCallDuration) - throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is outboundAsweredCall`) + // if (operation == 'inboundAnsweredCall' && !crmCallDuration) + // throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is inboundAnsweredCall`) + // if (operation == 'outboundAsweredCall' && !crmCallDuration) + // throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is outboundAsweredCall`) - await journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration,) + await journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration, crmFirstName) res.status(StatusCodes.OK).send() -} - +} + const install = async (req, res) => { const { authUrl, companyId } = req.query @@ -224,7 +224,7 @@ module.exports = { install, deleteCrm, deleteCompany, - testTemplate + testTemplate } diff --git a/backend/models/CRM.js b/backend/models/CRM.js index 22ac9ff..fb0a7c0 100644 --- a/backend/models/CRM.js +++ b/backend/models/CRM.js @@ -69,7 +69,7 @@ const CRMRestSchema = new Schema({ const AuthenticationSchema = new Schema({ type: { type: String, - enum: ['basic', 'bearer', 'oauth2'], + enum: ['basic', 'bearer', 'oauth2', "api_token"], default: 'bearer' }, userName: String, diff --git a/backend/utils/createCRMContact.js b/backend/utils/createCRMContact.js index 28ad3ca..e99212a 100644 --- a/backend/utils/createCRMContact.js +++ b/backend/utils/createCRMContact.js @@ -11,7 +11,7 @@ async function createCRMContact(companyId, crmFirstName, crmPhone, crmEmail = '' const { crmRest: rest, authentication } = crmConfig.crm const contact = await lookupContactByPhone(rest, authentication, crmPhone, companyId) - + if (contact.exist) continue await createContact(companyId, rest, authentication, crmPhone, crmFirstName, crmLastName, crmEmail,) diff --git a/backend/utils/createContact.js b/backend/utils/createContact.js index 1caa61b..2eec28e 100644 --- a/backend/utils/createContact.js +++ b/backend/utils/createContact.js @@ -8,9 +8,9 @@ const CRM = require('../models/CRM') const requestConfigHeader = require('./requestConfigHeader') const sendMessageSocket = require('./sendMessageSocket') -async function createContact(companyId, rest, authentication, crmPhone, crmFirstName = '', crmLastName = '', crmEmail = '', test = {}) { +async function createContact(companyId, rest, authentication, crmPhone, crmFirstName = 'unnamed', crmLastName = 'no surname', crmEmail = '', test = {}) { let { request, body, response } = findProperty(rest, 'createContactRecord') - + const { requestContentType, requestEncoding, requestType, responseType, url } = request body = flatten(body) @@ -43,14 +43,14 @@ async function createContact(companyId, rest, authentication, crmPhone, crmFirst //url, crmPhone, requestType, requestContentType, type, userName, passWord, token, crmClientId, data = '' const config = await requestConfigHeader(url, crmPhone, requestType, requestContentType, type, userName, passWord, token, crmClientId, body) - + if (test?.testing) { msg = `Tentanto criar contato de numero ${crmPhone} no crm` sendMessageSocket({ companyId, status: 'processing', data: { request: config, msg } }) } let { data } = await axios(config) - + data = flatten(data) let auxContactId @@ -64,6 +64,7 @@ async function createContact(companyId, rest, authentication, crmPhone, crmFirst break } } + if (auxContactId && !test?.testing) { const crm = await CRM.findOne({ companyId, crmBaseURL: new URL(url).hostname }) diff --git a/backend/utils/journaling.js b/backend/utils/journaling.js index 9c1dccc..7160ec4 100644 --- a/backend/utils/journaling.js +++ b/backend/utils/journaling.js @@ -5,7 +5,7 @@ const findProperty = require('./findProperty') const journalingRequest = require('./journalingRequest') -async function journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration = 0) { +async function journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration = 0, crmFirstName ='unnamed') { const crmFiles = await loadCRM(companyId) @@ -16,7 +16,7 @@ async function journaling(companyId, operation, crmPhone, crmAgent, crmCallDurat let contact = await lookupContactByPhone(rest, authentication, crmPhone, companyId) if (!contact.exist) { - contact = await createContact(companyId, rest, authentication, crmPhone) + contact = await createContact(companyId, rest, authentication, crmPhone, crmFirstName) } let { request, calls, response } = findProperty(rest, 'callJournaling') diff --git a/backend/utils/lookupCRMContactByPhone.js b/backend/utils/lookupCRMContactByPhone.js index cccb55d..c91957e 100644 --- a/backend/utils/lookupCRMContactByPhone.js +++ b/backend/utils/lookupCRMContactByPhone.js @@ -53,6 +53,24 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t } + if (!auxPhone && !auxContactId) { + for (const prop in data) { + + let _prop = prop.replace(/\.(\d+)(\.|$)/g, '[$1]$2') + + if (_prop == response?.phone?.trim()) { + auxPhone = data[prop].replace('+', '') + } + + if (_prop == response?.id?.trim()) { + auxContactId = data[prop] + } + + if (auxPhone && auxContactId) break + + } + } + if (auxPhone) { if (auxPhone && auxContactId) { diff --git a/backend/utils/requestConfigHeader.js b/backend/utils/requestConfigHeader.js index 4138eb2..6f67786 100644 --- a/backend/utils/requestConfigHeader.js +++ b/backend/utils/requestConfigHeader.js @@ -4,6 +4,16 @@ async function requestConfigHeader(url, crmPhone, requestType, requestContentTyp let config = {} url = url.replace('crmPhone', crmPhone) + + if (type == 'api_token') { + if (requestType.trim().toLowerCase() == 'post') { + url = `${url}?api_token=${token}` + } + else if (requestType.trim().toLowerCase() == 'get') { + url = `${url}&api_token=${token}` + } + } + let commonConfig = { method: requestType, url, @@ -47,7 +57,7 @@ async function requestConfigHeader(url, crmPhone, requestType, requestContentTyp config = { ...commonConfig, headers: { - ...commonConfig.headers, + ...commonConfig.headers, } } } diff --git a/backend/utils/templateValidator.js b/backend/utils/templateValidator.js index a0daef5..3208f09 100644 --- a/backend/utils/templateValidator.js +++ b/backend/utils/templateValidator.js @@ -23,7 +23,7 @@ async function templateValidator(crmPhoneTest, crm, companyId) { rest = crm.crmRest, authentication = crm.authentication, crmPhone = phoneTest, - crmFirstName = '', + crmFirstName = 'unnamed', crmLastName = '', crmEmail = '', test = { testing: true }) diff --git a/frontend/src/components/UploadFile.js b/frontend/src/components/UploadFile.js index 9c167be..7147179 100644 --- a/frontend/src/components/UploadFile.js +++ b/frontend/src/components/UploadFile.js @@ -63,6 +63,7 @@ const UploadFile = () => { setUploadStatus('Error uploading file.') setStatus('error') + console.log('error: ', error) setErrorResponse(error.response.data.msg) } }