feat: added feature to register whatsapp journaling from omnihit

master
adriano 2024-10-07 11:25:08 -03:00
parent 5b4406584b
commit b654ce11a9
8 changed files with 211 additions and 103 deletions

View File

@ -152,6 +152,29 @@
"response": {} "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.",
"ActivityDate": "YYYY-MM-DD",
"Status": "Completed",
"Priority": "Normal"
}
}
]
}
},
{ {
"redirectLink": { "redirectLink": {
"request": { "request": {

View File

@ -1,5 +1,6 @@
const path = require('path') const path = require('path')
const omnihitV2Integration = require('../data/omihitV2IntegrationCRM.json')
const { StatusCodes } = require("http-status-codes") const { StatusCodes } = require("http-status-codes")
const { createCRMContact, const { createCRMContact,
sendMessageSocket, sendMessageSocket,
@ -21,6 +22,8 @@ const CustomError = require('../errors')
const CRM_Contact = require('../models/CRM_Contact') const CRM_Contact = require('../models/CRM_Contact')
const axios = require('axios') const axios = require('axios')
const { get, set } = require('../utils/redisClient') const { get, set } = require('../utils/redisClient')
const { getContactIdChatwoot, createConversation, toggleConversationStatus } = require('../utils/ScheduleTicketCRM')
const timeStamp = require('../utils/toTimestamp')
const contactCreate = async (req, res) => { const contactCreate = async (req, res) => {
@ -292,6 +295,9 @@ const getCrms = async (req, res) => {
const webhook = async (req, res) => { const webhook = async (req, res) => {
const originIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress
console.log('========> Origem da requisição IP: ', originIP)
console.log('========> webhook req.body: ', JSON.stringify(req.body, null, 6)) console.log('========> webhook req.body: ', JSON.stringify(req.body, null, 6))
console.log('========> req.body: ', req.body) console.log('========> req.body: ', req.body)
@ -329,6 +335,9 @@ const webhook = async (req, res) => {
const webhook_crm = async (req, res) => { const webhook_crm = async (req, res) => {
const originIP = req.headers['x-forwarded-for'] || req.connection.remoteAddress
console.log('========> Crm Origem da requisição IP: ', originIP)
console.log('========> webhook crm req.body: ', JSON.stringify(req.body, null, 6)) console.log('========> webhook crm req.body: ', JSON.stringify(req.body, null, 6))
const responseXml = ` const responseXml = `
@ -347,22 +356,29 @@ const webhook_crm = async (req, res) => {
return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml) return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml)
} }
const url = req.body['soapenv:Envelope']['soapenv:Body']?.notifications?.EnterpriseUrl
console.log('========> salesforce url: ', url)
const crm = await CRM.findOne({ crmBaseURL: new URL(url.trim()).hostname })
const { companyId } = crm
console.log('========> crm companyId: ', companyId)
const whoId = sObject['sf:WhoId'] const whoId = sObject['sf:WhoId']
const EventSubtype = sObject['sf:EventSubtype'] const EventSubtype = sObject['sf:EventSubtype']
const StartDateTime = sObject['sf:StartDateTime'] const StartDateTime = sObject['sf:StartDateTime']
console.log('==========> crm EventSubtype: ', EventSubtype) console.log('==========> crm EventSubtype: ', EventSubtype)
console.log('==========> crm StartDateTime: ', StartDateTime) console.log('==========> crm StartDateTime: ', StartDateTime)
console.log('==========> crm StartDateTime timeStamp: ', timeStamp(StartDateTime)) console.log('==========> crm StartDateTime timeStamp: ', timeStamp(StartDateTime))
if (EventSubtype == 'Event') { if (EventSubtype == 'Event') {
const contact = await CRM_Contact.findOne({ const contact = await CRM_Contact.findOne({
companyId: "99", companyId,
crmBaseURL: 'nocompany-a9-dev-ed.develop.my.salesforce.com', crmBaseURL: new URL(url.trim()).hostname,
contactId: whoId contactId: whoId
}) })
@ -371,7 +387,15 @@ const webhook_crm = async (req, res) => {
const { phone } = contact const { phone } = contact
const contactIdChatwoot = await getContactIdChatwoot(phone) const obj = omnihitV2Integration.find(o => o.companyId == companyId)
if (obj) {
const { companyId,
omnihit: { accountId, api: { url, token } = {},
createConversation: { inbox_id, status, team_id } = {} } = {} } = obj
const contactIdChatwoot = await getContactIdChatwoot(url, token, phone)
if (!contactIdChatwoot) { if (!contactIdChatwoot) {
return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml) return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml)
@ -379,12 +403,16 @@ const webhook_crm = async (req, res) => {
console.log('==========> crm contactIdChatwoot: ', contactIdChatwoot) console.log('==========> crm contactIdChatwoot: ', contactIdChatwoot)
const ticketId = await createConversation(contactIdChatwoot) let data = { inbox_id, contact_id: contactIdChatwoot, status, team_id }
const omnihitConfig = { url, accountId, token }
const ticketId = await createConversation(data, omnihitConfig)
console.log('==========> crm ticketId: ', ticketId) console.log('==========> crm ticketId: ', ticketId)
await toggleConversationStatus({ "status": "snoozed", "snoozed_until": timeStamp(StartDateTime) }, ticketId) data = { "status": "snoozed", "snoozed_until": timeStamp(StartDateTime) }
await toggleConversationStatus(url, accountId, token, ticketId, data)
}
} }
return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml) return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml)
@ -406,82 +434,3 @@ module.exports = {
async function getContactIdChatwoot(phone) {
const config = {
method: 'get',
url: `http://172.31.187.47:3333/api/v1/accounts/15/contacts/search?q=${phone}`,
headers: {
'api_access_token': 'WpeGuicvuQ3pyLvYQ11eAxxL'
}
}
try {
const { data } = await axios(config)
return data.payload[0].id
} catch (error) {
console.error(error)
}
}
async function createConversation(contact_id) {
const data = JSON.stringify({
"inbox_id": "2",
"contact_id": `${contact_id}`,
"status": "pending",
"team_id": "1"
})
const config = {
method: 'post',
url: 'http://172.31.187.47:3333/api/v1/accounts/15/conversations',
headers: {
'api_access_token': 'WpeGuicvuQ3pyLvYQ11eAxxL',
'Content-Type': 'application/json'
},
data: data
}
try {
const { data } = await axios(config)
return data.id
} catch (error) {
console.error(error)
}
}
async function toggleConversationStatus(payload, ticketId) {
const config = {
method: 'post',
url: `http://172.31.187.47:3333/api/v1/accounts/15/conversations/${ticketId}/toggle_status`,
headers: {
'api_access_token': 'WpeGuicvuQ3pyLvYQ11eAxxL',
'Content-Type': 'application/json'
},
data: JSON.stringify(payload)
}
try {
const response = await axios(config)
console.log(JSON.stringify(response.data))
} catch (error) {
console.error(error)
}
}
function timeStamp(dateTimeISO8601) {
const date = new Date(dateTimeISO8601)
date.setHours(date.getUTCHours() - 3)
const timestamp = date.getTime() / 1000
return timestamp
}

View File

@ -0,0 +1,11 @@
const omnihitV2Integration = require('../data/omihitV2IntegrationCRM.json')
const obj = omnihitV2Integration.find(o => o.companyId === "99")
if (obj) {
console.log(obj)
const { companyId, omnihit: { accountId, api: { url, token } = {}, createConversation: { inbox_id, status, team_id } = {} } = {} } = obj
console.log('companyId: ', companyId, ' accountId: ', accountId, ' url: ', url, ' token: ', token, ' inbox_id: ', inbox_id, ' status: ', status, ' team_id: ', team_id)
}

View File

@ -0,0 +1,19 @@
[
{
"companyId":"99",
"omnihit": {
"accountId":"15",
"api":{
"url":"http://172.31.187.47:3333",
"token": "WpeGuicvuQ3pyLvYQ11eAxxL"
},
"createConversation":{
"inbox_id": "2",
"status":"pending",
"team_id": "1"
}
}
}
]

View File

@ -38,12 +38,21 @@ const CallsSchema = new Schema({
outboundUnansweredCall: Object outboundUnansweredCall: Object
}) })
const ChatsSchema = new Schema({
chatDone: Object,
})
const CallJournalingSchema = new Schema({ const CallJournalingSchema = new Schema({
request: RequestSchema, request: RequestSchema,
calls: [CallsSchema], calls: [CallsSchema],
response: Object response: Object
}) })
const ChatJournalingSchema = new Schema({
request: RequestSchema,
chats: [ChatsSchema],
response: Object
})
const RedirectUrlSchema = new Schema({ const RedirectUrlSchema = new Schema({
@ -53,12 +62,6 @@ const RedirectUrlSchema = new Schema({
} }
}) })
// const redirectLinkSchema = new Schema({
// request: RedirectUrlSchema,
// })
// Define main schema // Define main schema
const CRMRestSchema = new Schema({ const CRMRestSchema = new Schema({
@ -91,7 +94,8 @@ const CRMRestSchema = new Schema({
redirectLink: { redirectLink: {
request: RedirectUrlSchema request: RedirectUrlSchema
}, },
callJournaling: CallJournalingSchema callJournaling: CallJournalingSchema,
chatJournaling: ChatJournalingSchema
}) })
const AuthenticationSchema = new Schema({ const AuthenticationSchema = new Schema({

View File

@ -0,0 +1,69 @@
const axios = require('axios')
async function getContactIdChatwoot(url, token, phone) {
const config = {
method: 'get',
url: `${url}/api/v1/accounts/15/contacts/search?q=${phone}`,
headers: {
'api_access_token': token
}
}
try {
const { data } = await axios(config)
return data.payload[0].id
} catch (error) {
console.error(error)
}
}
async function createConversation(data, omnihitConfig) {
const { url, accountId, token } = omnihitConfig
const config = {
method: 'post',
url: `${url}/api/v1/accounts/${accountId}/conversations`,
headers: {
'api_access_token': token,
'Content-Type': 'application/json'
},
data: data
}
try {
const { data } = await axios(config)
return data.id
} catch (error) {
console.error(error)
}
}
async function toggleConversationStatus(url, accountId, token, ticketId, payload) {
const config = {
method: 'post',
url: `${url}/api/v1/accounts/${accountId}/conversations/${ticketId}/toggle_status`,
headers: {
'api_access_token': token,
'Content-Type': 'application/json'
},
data: JSON.stringify(payload)
}
try {
const response = await axios(config)
console.log(JSON.stringify(response.data))
} catch (error) {
console.error(error)
}
}
module.exports = {
getContactIdChatwoot,
createConversation,
toggleConversationStatus
}

View File

@ -9,6 +9,7 @@ const createTicket = require('./createTicket')
const lookupCRMTicket = require('./lookupCRMTicket') const lookupCRMTicket = require('./lookupCRMTicket')
const sendEventTicketCreatedToSocket = require('./sendEventTicketCreatedToSocket') const sendEventTicketCreatedToSocket = require('./sendEventTicketCreatedToSocket')
const journalingRequest = require('./journalingRequest')
async function ticketCRM(companyId, crmPhone, crmAgent, crmFirstName = 'Username') { async function ticketCRM(companyId, crmPhone, crmAgent, crmFirstName = 'Username') {
@ -21,6 +22,26 @@ async function ticketCRM(companyId, crmPhone, crmAgent, crmFirstName = 'Username
const { crmRest: rest, authentication } = crmConfig.crm const { crmRest: rest, authentication } = crmConfig.crm
// Record whatsapp conversation that happened in omnihit v2
let chatJournaling = findProperty(rest, 'chatJournaling')
console.log('===============> chatJournaling: ', chatJournaling)
if (chatJournaling) {
let contact = await _lookupContact(rest, authentication, crmPhone, companyId, crmFirstName)
const { contactId, created } = contact
let { request, chats, response } = chatJournaling
let body = findProperty(chats, 'chatDone')
await journalingRequest(request, body, crmCallDuration = 0, contact, crmAgent, crmPhone, authentication, rest)
}
// Send the edited contact/lead link url to hitphone to open on another browser tab // Send the edited contact/lead link url to hitphone to open on another browser tab
let redirectLink = findProperty(rest, 'redirectLink') let redirectLink = findProperty(rest, 'redirectLink')

View File

@ -0,0 +1,12 @@
function timeStamp(dateTimeISO8601) {
const date = new Date(dateTimeISO8601)
date.setHours(date.getUTCHours() - 3)
const timestamp = date.getTime() / 1000
return timestamp
}
module.exports = timeStamp