refactor: code adjustment
							parent
							
								
									a1195810fe
								
							
						
					
					
						commit
						ce94c22f0a
					
				|  | @ -0,0 +1,208 @@ | |||
| { | ||||
|   "authentication": { | ||||
|     "type": "oauth2", | ||||
|     "crmClientId": "3MVG9JJwBBbcN47Kv0Z7EuNd19INI1Bhe7uX_Wz6M0VlMyWJD4xPKTtn_b39bGn6LmdSkKJ.aLNGdV1brj16C", | ||||
|     "crmClientSecret": "870E8D51A1CA06896D966A3D92ABD885346DAD4428926E965776C479055969E7", | ||||
|     "crmScopes": "full refresh_token", | ||||
|     "crmPhoneTest": "5514983253326" | ||||
|   }, | ||||
|   "crmRest": [ | ||||
|     { | ||||
|       "authorizationEndpoint": { | ||||
|         "request": { | ||||
|           "requestContentType": "empty", | ||||
|           "requestEncoding": "empty", | ||||
|           "requestType": "Get", | ||||
|           "responseType": "empty", | ||||
|           "url": "https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id=crmClientId&code_challenge=bDXEJ0wxr0s369lGxHwewLULiOuyl6Y3W7QZABmn2S4&redirect_uri=crmRedirectURI&scope=crmScopes&code_challenge_method=S256" | ||||
|         }, | ||||
|         "body": {}, | ||||
|         "response": {} | ||||
|       } | ||||
|     }, | ||||
|     { | ||||
|       "tokenEndpoint": { | ||||
|         "request": { | ||||
|           "requestContentType": "none", | ||||
|           "requestEncoding": "Json", | ||||
|           "requestType": "Post", | ||||
|           "responseType": "Json", | ||||
|           "url": "https://login.salesforce.com/services/oauth2/token" | ||||
|         }, | ||||
|         "body": {}, | ||||
|         "response": {} | ||||
|       } | ||||
|     }, | ||||
|     { | ||||
|       "createContactRecord": { | ||||
|         "request": { | ||||
|           "requestContentType": "application/json", | ||||
|           "requestEncoding": "Json", | ||||
|           "requestType": "Post", | ||||
|           "responseType": "Json", | ||||
|           "url": "https://nocompany-a9-dev-ed.develop.my.salesforce.com/services/data/v61.0/sobjects/Contact" | ||||
|         }, | ||||
|         "body": { | ||||
|           "Phone": "crmPhone", | ||||
|           "LastName": "crmLastName", | ||||
|           "FirstName": "crmFirstName" | ||||
|         }, | ||||
|         "response": { | ||||
|           "id": "id" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     { | ||||
|       "lookupContactByPhone": { | ||||
|         "request": { | ||||
|           "requestContentType": "application/json", | ||||
|           "requestEncoding": "Json", | ||||
|           "requestType": "Get", | ||||
|           "responseType": "Json", | ||||
|           "url": "https://nocompany-a9-dev-ed.develop.my.salesforce.com/services/data/v61.0/query/?q=SELECT+Id,+Phone,+AccountId+FROM+Contact+WHERE+Phone='crmPhone'" | ||||
|         }, | ||||
|         "response": { | ||||
|           "phone": "records[0].Phone", | ||||
|           "id": "records[0].Id", | ||||
|           "accountId": "records[0].AccountId", | ||||
|           "name": "records[0].Name" | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     { | ||||
|       "callJournaling": { | ||||
|         "request": { | ||||
|           "requestContentType": "application/json", | ||||
|           "requestEncoding": "Json", | ||||
|           "requestType": "Post", | ||||
|           "responseType": "Json", | ||||
|           "url": "https://nocompany-a9-dev-ed.develop.my.salesforce.com/services/data/v61.0/sobjects/Task" | ||||
|         }, | ||||
|         "calls": [ | ||||
|           { | ||||
|             "inboundAnsweredCall": { | ||||
|               "Subject": "Call Journal", | ||||
|               "WhoId": "crmContactId", | ||||
|               "Description": "Ligação recebida", | ||||
|               "Status": "Completed", | ||||
|               "Priority": "Normal", | ||||
|               "CallType": "Outbound", | ||||
|               "CallDurationInSeconds": { | ||||
|                 "_prop": "crmCallDuration", | ||||
|                 "_type": "number", | ||||
|                 "_format": "seconds" | ||||
|               }, | ||||
|               "ActivityDate": "YYYY-MM-DD", | ||||
|               "TaskSubtype": "Call" | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|             "inboundMissedCall": { | ||||
|               "Subject": "Call Journal", | ||||
|               "WhoId": "crmContactId", | ||||
|               "Description": "Ligação recebida perdida", | ||||
|               "Status": "Completed", | ||||
|               "Priority": "Normal", | ||||
|               "CallType": "Outbound", | ||||
|               "CallDurationInSeconds": { | ||||
|                 "_prop": "crmCallDuration", | ||||
|                 "_type": "number", | ||||
|                 "_format": "seconds" | ||||
|               }, | ||||
|               "ActivityDate": "YYYY-MM-DD", | ||||
|               "TaskSubtype": "Call" | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|             "outboundAnsweredCall": { | ||||
|               "Subject": "Call Journal", | ||||
|               "WhoId": "crmContactId", | ||||
|               "Description": "Ligação realizada", | ||||
|               "Status": "Completed", | ||||
|               "Priority": "Normal", | ||||
|               "CallType": "Outbound", | ||||
|               "CallDurationInSeconds": { | ||||
|                 "_prop": "crmCallDuration", | ||||
|                 "_type": "number", | ||||
|                 "_format": "seconds" | ||||
|               }, | ||||
|               "ActivityDate": "YYYY-MM-DD", | ||||
|               "TaskSubtype": "Call" | ||||
|             } | ||||
|           }, | ||||
|           { | ||||
|             "outboundUnansweredCall": { | ||||
|               "Subject": "Call Journal", | ||||
|               "WhoId": "crmContactId", | ||||
|               "Description": "Ligação realizada nao atendida", | ||||
|               "Status": "Completed", | ||||
|               "Priority": "Normal", | ||||
|               "CallType": "Outbound", | ||||
|               "CallDurationInSeconds": { | ||||
|                 "_prop": "crmCallDuration", | ||||
|                 "_type": "number", | ||||
|                 "_format": "seconds" | ||||
|               }, | ||||
|               "ActivityDate": "YYYY-MM-DD", | ||||
|               "TaskSubtype": "Call" | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         "response": {} | ||||
|       } | ||||
|     },     | ||||
|     { | ||||
|       "chatJournaling": { | ||||
|         "request": { | ||||
|           "requestContentType": "application/json", | ||||
|           "requestEncoding": "Json", | ||||
|           "requestType": "Post", | ||||
|           "responseType": "Json", | ||||
|           "url": "https://nocompany-a9-dev-ed.develop.my.salesforce.com/services/data/v61.0/sobjects/Task" | ||||
|         }, | ||||
|         "chats": [ | ||||
|           { | ||||
|             "chatDone":{ | ||||
|               "WhoId": "crmContactId",   | ||||
|               "Subject": "WhatsApp Chat", | ||||
|               "Description": "Conversation started via WhatsApp. Conversation link: chatLink", | ||||
|               "ActivityDate": "YYYY-MM-DD", | ||||
|               "Status": "Completed",    | ||||
|               "Priority": "Normal"  | ||||
|             }             | ||||
|           } | ||||
|         ] | ||||
|       } | ||||
|     },      | ||||
|     { | ||||
|       "redirectLink": { | ||||
|         "request": { | ||||
|           "url": "https://nocompany-a9-dev-ed.develop.lightning.force.com/lightning/r/Lead/crmContactId/edit?count=1&backgroundContext=%2Flightning%2Fr%2FLead%2F00Qak0000098YFhEAM%2Fview" | ||||
|         } | ||||
|       } | ||||
|     },      | ||||
|     { | ||||
|       "createCase": { | ||||
|         "request": { | ||||
|           "requestContentType": "application/json", | ||||
|           "requestEncoding": "Json", | ||||
|           "requestType": "Post", | ||||
|           "responseType": "Json", | ||||
|           "url": "https://nocompany-a9-dev-ed.develop.my.salesforce.com/services/data/v61.0/sobjects/Case" | ||||
|         }, | ||||
|         "body": { | ||||
| 
 | ||||
|           "Subject": "Assunto do Caso teste", | ||||
|           "Description": "Descrição detalhada do caso test", | ||||
|           "Status": "Novo", | ||||
|           "Priority": "Alta", | ||||
|           "Departamento__c": "Financeiro" | ||||
|   | ||||
|         }, | ||||
|         "response": { | ||||
|           "id": "id" | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
| } | ||||
|  | @ -408,11 +408,11 @@ const createTicket = async (req, res) => { | |||
|         const ticketIdMatch = crmTicketLink.ticketId.match(/ticket\/(\d+)/); | ||||
|         if (ticketIdMatch && ticketIdMatch[1]) { | ||||
|             const ticketId = ticketIdMatch[1]; | ||||
|             await set(crmPhone, ticketId);  | ||||
|             await set(crmPhone, ticketId, 10800); // excluido após 3 horas(10800 segundos) caso não receba a requisição de trascrição
 | ||||
|             console.log(`TicketId ${ticketId} para crmPhone ${crmPhone} salvo no Redis com sucesso.`); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|    | ||||
|     return res.status(StatusCodes.OK).json({ crmTicketLinks }) | ||||
| } | ||||
| 
 | ||||
|  | @ -556,42 +556,7 @@ const webhook_crm = async (req, res) => { | |||
| 
 | ||||
|     return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml) | ||||
| } | ||||
| 
 | ||||
| const associateTicketToCaller = async (req, res) => { | ||||
|     try { | ||||
|         const { callerId, ticketId } = req.body; | ||||
| 
 | ||||
|         if (!callerId || !ticketId) { | ||||
|             return res.status(StatusCodes.BAD_REQUEST).json({  | ||||
|                 error: 'Campos obrigatórios ausentes. É necessário fornecer callerId e ticketId.'  | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
|         // Remove o zero inicial do número se existir
 | ||||
|         const formattedCallerId = removeZeroInicial(callerId); | ||||
|          | ||||
|         // Adiciona o prefixo 55 se não existir
 | ||||
|         const fullCallerId = formattedCallerId.startsWith('55') ? formattedCallerId : `55${formattedCallerId}`; | ||||
| 
 | ||||
|         // Salva a associação no Redis com um tempo de expiração de 5 minutos (300 segundos)
 | ||||
|         await set(fullCallerId, ticketId, 300); | ||||
| 
 | ||||
|         console.log(`Ticket ${ticketId} associado ao número ${fullCallerId} com sucesso.`); | ||||
| 
 | ||||
|         return res.status(StatusCodes.OK).json({  | ||||
|             message: 'Ticket associado com sucesso', | ||||
|             callerId: fullCallerId, | ||||
|             ticketId | ||||
|         }); | ||||
| 
 | ||||
|     } catch (error) { | ||||
|         console.error('Erro ao associar ticket:', error); | ||||
|         Sentry.captureException(error); | ||||
|         return res.status(StatusCodes.INTERNAL_SERVER_ERROR).json({  | ||||
|             error: 'Erro ao processar a associação do ticket'  | ||||
|         }); | ||||
|     } | ||||
| }; | ||||
|   | ||||
| 
 | ||||
| const checkTicketByCrmPhone = async (req, res) => { | ||||
|     const { crmPhone } = req.query; | ||||
|  | @ -632,8 +597,7 @@ module.exports = { | |||
|     webhook_crm, | ||||
|     sfCreateCase, | ||||
|     sfUpdateCase, | ||||
|     createTicket, | ||||
|     associateTicketToCaller, | ||||
|     createTicket,  | ||||
|     checkTicketByCrmPhone | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,55 +1,50 @@ | |||
| const redis = require('redis'); | ||||
| const HubspotService = require('../services/hubspotService'); | ||||
| require('dotenv').config(); | ||||
| 
 | ||||
| const redisClient = redis.createClient({ | ||||
|   url: process.env.REDIS_URI | ||||
| }); | ||||
| 
 | ||||
| redisClient.on('error', (err) => console.log('Redis Client Error', err)); | ||||
| 
 | ||||
| (async () => { | ||||
|   if (!redisClient.isOpen) { | ||||
|     await redisClient.connect(); | ||||
|   } | ||||
| })(); | ||||
| const HubspotService = require('../services/hubspotService');  | ||||
| const { get, del } = require('../utils/redisClient')  | ||||
| 
 | ||||
| const hubspotService = new HubspotService(); | ||||
| 
 | ||||
| exports.receiveTranscription = async (req, res) => { | ||||
|   try { | ||||
|     const { callerId, uniqueId, transcription, recordingUrl } = req.body; | ||||
| const receiveTranscription = async (req, res) => { | ||||
|   try {  | ||||
| 
 | ||||
|     if (!callerId || !uniqueId || !transcription || !recordingUrl) { | ||||
|     const { crmPhone, uniqueId, transcription, recordingUrl, companyId } = req.body; | ||||
|    | ||||
|     if (!crmPhone || !uniqueId || !transcription || !recordingUrl) { | ||||
|       return res.status(400).json({ error: 'Campos obrigatórios ausentes.' }); | ||||
|     } | ||||
| 
 | ||||
|     console.log(`Recebida transcrição para callerId: ${callerId}, uniqueId: ${uniqueId}`); | ||||
|     console.log(`Recebida transcrição para crmPhone: ${crmPhone}, uniqueId: ${uniqueId}`); | ||||
|     console.log('Transcrição:', transcription.summary); | ||||
| 
 | ||||
|     // 1. Buscar ticketId no Redis
 | ||||
|     const ticketId = await redisClient.get(callerId); | ||||
| 
 | ||||
|     const ticketId = await get(crmPhone); | ||||
|    | ||||
|     if (!ticketId) { | ||||
|       console.warn(`Nenhum ticketId encontrado no Redis para o callerId: ${callerId}. A transcrição será salva como uma nota sem associação ao ticket.`); | ||||
|       console.warn(`Nenhum ticketId encontrado no Redis para o crmPhone: ${crmPhone}. A transcrição será salva como uma nota sem associação ao ticket.`); | ||||
|     } | ||||
| 
 | ||||
|   | ||||
|     // 2. Buscar ou criar contato no HubSpot
 | ||||
|     const contact = await hubspotService.createContactIfNotExists(callerId); | ||||
|     const contact = await hubspotService.createContactIfNotExists(companyId, crmPhone);   | ||||
| 
 | ||||
|     // 3. Criar nota no HubSpot e associar ao contato e ao ticket (se existir)
 | ||||
|     await hubspotService.createCallNote(contact.id, { | ||||
|     await hubspotService.createCallNote(contact.contactId, { | ||||
|       transcription: `${transcription.client || ''}\n${transcription.agent || ''}`, | ||||
|       summary: transcription.summary, | ||||
|       recordingUrl, | ||||
|       callerId, | ||||
|       crmPhone, | ||||
|       uniqueId, | ||||
|       ticketId | ||||
|     }); | ||||
| 
 | ||||
|     await del(crmPhone) | ||||
| 
 | ||||
|     return res.status(200).json({ message: 'Transcrição recebida e processada com sucesso!' }); | ||||
|   } catch (error) { | ||||
|     console.error('Erro ao receber transcrição:', error?.response?.data || error.message || error); | ||||
|     return res.status(500).json({ error: 'Erro ao processar a transcrição.' }); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| module.exports ={ | ||||
|   receiveTranscription | ||||
| } | ||||
|  | @ -3,8 +3,7 @@ const router = express.Router() | |||
| const { authorization, } = require('../middleware/authentication') | ||||
| const { contactCreate, sfCreateCase, sfUpdateCase, createTicket, testTemplate, webhook_crm, uploadCrmConfig, callJournaling, oauthCallBack, install, deleteCrm, deleteCompany, getCrms, webhook, checkTicketByCrmPhone } = require('../controllers/crmController') | ||||
| const { receiveTranscription } = require('../controllers/transcriptionController') | ||||
| const { fileUpload } = require("../utils") | ||||
| const { associateTicketToCaller } = require('../controllers/crmController'); | ||||
| const { fileUpload } = require("../utils")  | ||||
| 
 | ||||
| router.route('/create-contact').post(authorization, contactCreate) | ||||
| router.route('/create-ticket').post(authorization, createTicket) | ||||
|  | @ -19,7 +18,7 @@ router.route('/install').get(install) | |||
| router.route('/test').post(testTemplate) | ||||
| router.route('/webhook').post(webhook) | ||||
| router.route('/webhook-crm').post(webhook_crm) | ||||
| router.route('/transcriptions').post( receiveTranscription) | ||||
| router.route('/transcriptions').post(authorization, receiveTranscription) | ||||
| router.route('/:companyId').get(authorization, getCrms) | ||||
| router.route('/tickets/check-by-crmphone').get(authorization, checkTicketByCrmPhone) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,9 @@ | |||
| const axios = require('axios'); | ||||
| const Logger = console;  | ||||
| const Logger = console; | ||||
| require('dotenv').config(); | ||||
| const loadCRM = require('../utils/loadCRM') | ||||
| const lookupContactByPhone = require('../utils/lookupCRMContactByPhone') | ||||
| const createContact = require('../utils/createContact') | ||||
| 
 | ||||
| /** | ||||
|  * Serviço para integração com a API do HubSpot. | ||||
|  | @ -112,22 +115,26 @@ Link da Gravação: ${recordingUrl} | |||
|   /** | ||||
|    * Cria um contato com o número informado caso não exista. | ||||
|    *  | ||||
|    * @param {string} phoneNumber - Número de telefone do contato. | ||||
|    * @param {string} crmPhone - Número de telefone do contato. | ||||
|    * @returns {Promise<Object>} - Contato existente ou novo contato criado. | ||||
|    */ | ||||
|   async createContactIfNotExists(phoneNumber) { | ||||
|     const existing = await this.findContactByPhone(phoneNumber); | ||||
|     if (existing) return existing; | ||||
|   async createContactIfNotExists(companyId, crmPhone) { | ||||
| 
 | ||||
|     const response = await this.client.post('/crm/v3/objects/contacts', { | ||||
|       properties: { | ||||
|         phone: phoneNumber, | ||||
|          | ||||
|     const crmFiles = await loadCRM(companyId) | ||||
| 
 | ||||
|     if (crmFiles.length > 0) { | ||||
| 
 | ||||
|       const { crmRest: rest, authentication } = crmFiles[0].crm | ||||
| 
 | ||||
|       let contact = await lookupContactByPhone(rest, authentication, crmPhone, companyId) | ||||
| 
 | ||||
|       if (!contact.exist) { | ||||
|         contact = await createContact(companyId, rest, authentication, crmPhone) | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     this.logger.log(`Contato criado para o número ${phoneNumber}`); | ||||
|     return response.data; | ||||
|       return contact | ||||
|     } | ||||
| 
 | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue