feat: added feature to register whatsapp journaling from omnihit
parent
5b4406584b
commit
b654ce11a9
|
@ -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": {
|
||||||
|
|
|
@ -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,20 +387,32 @@ 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 (!contactIdChatwoot) {
|
if (obj) {
|
||||||
return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml)
|
|
||||||
|
const { companyId,
|
||||||
|
omnihit: { accountId, api: { url, token } = {},
|
||||||
|
createConversation: { inbox_id, status, team_id } = {} } = {} } = obj
|
||||||
|
|
||||||
|
const contactIdChatwoot = await getContactIdChatwoot(url, token, phone)
|
||||||
|
|
||||||
|
if (!contactIdChatwoot) {
|
||||||
|
return res.set('Content-Type', 'text/xml').status(StatusCodes.OK).send(responseXml)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('==========> crm contactIdChatwoot: ', 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)
|
||||||
|
|
||||||
|
data = { "status": "snoozed", "snoozed_until": timeStamp(StartDateTime) }
|
||||||
|
|
||||||
|
await toggleConversationStatus(url, accountId, token, ticketId, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('==========> crm contactIdChatwoot: ', contactIdChatwoot)
|
|
||||||
|
|
||||||
const ticketId = await createConversation(contactIdChatwoot)
|
|
||||||
|
|
||||||
console.log('==========> crm ticketId: ', ticketId)
|
|
||||||
|
|
||||||
await toggleConversationStatus({ "status": "snoozed", "snoozed_until": timeStamp(StartDateTime) }, ticketId)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
|
@ -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({
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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')
|
||||||
|
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue