feat: implementation to create ticket by for contacts and individual customers on sap crm to client codWeb 4953 Gradezco colombia

master
adriano 2025-10-21 09:18:51 -03:00
parent 900074adb1
commit d05bc4c381
14 changed files with 789 additions and 169 deletions

View File

@ -0,0 +1,241 @@
{
"authentication": {
"type": "basic",
"userName": "_INTEGRACAO_",
"passWord": "p3G44K10366",
"crmPhoneTest": "+5511998765123"
},
"crmRest": [
{
"createContactRecord": {
"request": {
"requestContentType": "application/json",
"requestEncoding": "Json",
"requestType": "Post",
"responseType": "Json",
"url": "https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/ContactCollection"
},
"body": {
"LastName": "crmLastName",
"FirstName": "crmFirstName",
"Phone": "+crmPhone",
"Mobile": "+crmPhone",
"AccountID": "1000320"
},
"response": {
"id": "d.results.ContactID",
"objectId": "d.results.ObjectID"
}
}
},
{
"createContactRecord2": {
"request": {
"requestContentType": "application/json",
"requestEncoding": "Json",
"requestType": "Post",
"responseType": "Json",
"url": "https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/IndividualCustomerCollection"
},
"body": {
"RoleCode": "CRM000",
"LastName": "crmLastName",
"FirstName": "crmFirstName",
"Phone": "+crmPhone",
"Mobile": "+crmPhone"
},
"response": {
"id": "d.results.CustomerID",
"objectId": "d.results.ObjectID"
}
}
},
{
"lookupContactByPhone": {
"request": {
"requestContentType": "application/json",
"requestEncoding": "Json",
"requestType": "Get",
"responseType": "Json",
"url": "https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/ContactCollection?$select=ObjectID,FirstName,LastName,Email,StatusCode,AccountID,StatusCodeText,Phone,Mobile,NormalisedMobile,ContactID&$filter=NormalisedMobile eq '%2BcrmPhone'"
},
"response": {
"phone": "d.results[0].NormalisedMobile",
"id": "d.results[0].ContactID",
"objectId": "d.results[0].ObjectID",
"accountId": "d.results[0].AccountID"
}
}
},
{
"lookupContactByPhone2": {
"request": {
"requestContentType": "application/json",
"requestEncoding": "Json",
"requestType": "Get",
"responseType": "Json",
"url": "https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/IndividualCustomerCollection?%24select=ObjectID%2CFirstName%2CLastName%2CEmail%2CPhone%2CMobile%2CNormalisedPhone%2CNormalisedMobile%2CCustomerID&%24filter=NormalisedPhone%20eq%20%27%2BcrmPhone%27"
},
"response": {
"phone": "d.results[0].NormalisedPhone",
"id": "d.results[0].CustomerID",
"objectId": "d.results[0].ObjectID"
}
}
},
{
"callJournaling": {
"request": {
"requestContentType": "application/json",
"requestEncoding": "Json",
"requestType": "Post",
"responseType": "Json",
"url": "https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/PhoneCallCollection"
},
"calls": [
{
"inboundAnsweredCall": {
"Subject": "Ligação recebida",
"Status": "1",
"InitiatorCode": "2",
"DataOriginTypeCode": "3",
"MainContactPartyID": "crmContactId"
}
},
{
"outboundAnsweredCall": {
"Subject": "Ligação Realizada",
"Status": "1",
"InitiatorCode": "3",
"DataOriginTypeCode": "3",
"MainContactPartyID": "crmContactId"
}
}
]
}
},
{
"chatJournaling": {
"request": {
"requestContentType": "application/json",
"requestEncoding": "Json",
"requestType": "Post",
"responseType": "Json",
"url": "https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/TasksCollection"
},
"chats": [
{
"chatDone": {
"Subject": "URL de la conversación en omnihit",
"Status": "1",
"PriorityCode": "3",
"MainContactPartyID": "crmContactId",
"TasksTextCollection": {
"results": [
{
"Text": "Conversación iniciada por WhatsApp. URL de la conversación de Ominhit: chatLink",
"TypeCode": "10002"
}
]
}
}
}
]
}
},
{
"redirectLink": {
"request": {
"url": "https://my365398.crm.ondemand.com/sap/public/byd/runtime?bo_ns=http%3A%2F%2Fsap.com%2FthingTypes&bo=COD_GENERIC&node=Root&operation=OnExtInspect&param.Type=COD_CONTACT_TT&param.InternalID=crmContactId"
}
}
},
{
"redirectLink2": {
"request": {
"url": "https://my365398.crm.ondemand.com/sap/ap/ui/clogin?saml2=disabled&app.component=%2fSAP_UI_CT%2fMain%2froot.uiccwoc&rootWindow=X&redirectUrl=%2fsap%2fpublic%2fbyd%2fruntime&supressAutoLogon=true&sap-ui-language=en_us#Nav/1/crmTicketId"
}
}
},
{
"createTicketRecord": {
"request": {
"requestContentType": "application/json",
"requestEncoding": "Json",
"requestType": "Post",
"responseType": "Json",
"url": "https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/ServiceRequestCollection"
},
"body": {
"Name": "Nova Solicitação de Serviço API (Com Contato) test 09",
"ServicePriorityCode": "3",
"ServiceRequestUserLifeCycleStatusCode": "1",
"DataOriginTypeCode": "3",
"BuyerPartyID": "crmAccountId",
"BuyerMainContactPartyID": "crmContactId",
"ServiceIssueCategoryID": "Z1000"
},
"response": {
"id": "d.results.ID",
"objectId": "d.results.ObjectID"
}
}
},
{
"createTicketRecord2": {
"request": {
"requestContentType": "application/json",
"requestEncoding": "Json",
"requestType": "Post",
"responseType": "Json",
"url": "https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/ServiceRequestCollection"
},
"body": {
"Name": "Nova Solicitação de Serviço API (Com Contato) individual customers 1",
"ServicePriorityCode": "3",
"ServiceRequestUserLifeCycleStatusCode": "1",
"DataOriginTypeCode": "3",
"BuyerPartyID": "crmContactId",
"ReportedForPartyID": "crmContactId",
"ServiceIssueCategoryID": "Z1000"
},
"response": {
"id": "d.results.ID",
"objectId": "d.results.ObjectID"
}
}
},
{
"lookupTicket": {
"request": {
"requestContentType": "application/json",
"requestEncoding": "Json",
"requestType": "Get",
"responseType": "Json",
"url": "https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/ServiceRequestCollection?$filter=BuyerMainContactPartyID%20eq%20%crmContactId%27%20and%20ServiceRequestUserLifeCycleStatusCode%20eq%20%271%27"
},
"response": {
"id": "d.results[0].ID",
"objectId": "d.results[0].ObjectID",
"status": "d.results[0].ServiceRequestUserLifeCycleStatusCodeText"
}
}
},
{
"lookupTicket2": {
"request": {
"requestContentType": "application/json",
"requestEncoding": "Json",
"requestType": "Get",
"responseType": "Json",
"url": "https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/ServiceRequestCollection?$filter=BuyerPartyID%20eq%20%27crmContactId%27%20and%20ServiceRequestUserLifeCycleStatusCode%20eq%20%271%27"
},
"response": {
"id": "d.results[0].ID",
"objectId": "d.results[0].ObjectID",
"status": "d.results[0].ServiceRequestUserLifeCycleStatusCodeText"
}
}
}
]
}

View File

@ -32,6 +32,7 @@ const sfcase = require('../utils/sfCase')
const sfCaseUpdate = require('../utils/sfCaseUpdate')
const removeZeroInicial = require('../utils/removeZeroInicial')
const lookupContactByEmail = require('../utils/lookupCRMContactByEmail')
const generateC4CServiceRequestDeepLinkBase64 = require('../utils/generateC4CServiceRequestDeepLinkBase64')
const contactCreate = async (req, res) => {
@ -43,7 +44,7 @@ const contactCreate = async (req, res) => {
if (!companyId || (!crmPhone && !crmEmail)) {
return res.status(StatusCodes.BAD_REQUEST).json({
message: 'companyId e crmPhone ou crmEmail são obrigatórios.'
});
})
}
await createCRMContact(companyId, crmFirstName, crmPhone, crmEmail, crmLastName, dynamicBodyRequest)
@ -72,33 +73,33 @@ const contactCreate = async (req, res) => {
// res.status(StatusCodes.OK).json({ exist: false })
// }
const checkContact = async (req, res) => {
const { companyId, crmPhone, crmEmail } = req.body;
const { companyId, crmPhone, crmEmail } = req.body
if (!companyId || (!crmPhone && !crmEmail)) {
return res.status(StatusCodes.BAD_REQUEST).json({
message: 'companyId and either crmPhone or crmEmail are required.'
});
})
}
const crmFiles = await loadCRM(companyId);
const crmFiles = await loadCRM(companyId)
if (crmFiles.length > 0) {
const { crmRest: rest, authentication } = crmFiles[0].crm;
let contact = null;
const { crmRest: rest, authentication } = crmFiles[0].crm
let contact = null
if (crmPhone) {
contact = await lookupContactByPhone(rest, authentication, crmPhone, companyId);
contact = await lookupContactByPhone(rest, authentication, crmPhone, companyId)
}
if (!contact?.exist && crmEmail) {
contact = await lookupContactByEmail(rest, authentication, crmEmail, companyId);
contact = await lookupContactByEmail(rest, authentication, crmEmail, companyId)
}
if (contact?.exist) {
return res.status(StatusCodes.OK).json({ exist: contact.exist });
return res.status(StatusCodes.OK).json({ exist: contact.exist })
}
}
res.status(StatusCodes.OK).json({ exist: false });
};
res.status(StatusCodes.OK).json({ exist: false })
}
// const contactActivity = async (req, res) => {
// const { companyId, crmPhone, ticketId } = req.body
@ -117,14 +118,14 @@ const checkContact = async (req, res) => {
// }
const contactActivity = async (req, res) => {
// 1. Recebe 'crmEmail' do corpo da requisição
const { companyId, crmPhone, crmEmail, ticketId, dynamicBodyRequest } = req.body;
const { companyId, crmPhone, crmEmail, ticketId, dynamicBodyRequest } = req.body
// 2. Ajusta a validação para que 'crmPhone' ou 'crmEmail' seja obrigatório
// Se nenhum dos dois for fornecido, a requisição é inválida.
if (!crmPhone && !crmEmail) {
return res.status(StatusCodes.BAD_REQUEST).send({
message: "crmPhone ou crmEmail é obrigatório."
});
})
}
// A validação para 'companyId' e 'ticketId' continua, se forem obrigatórios
@ -139,10 +140,10 @@ const contactActivity = async (req, res) => {
ticketId,
crmEmail,
dynamicBodyRequest
);
)
res.status(StatusCodes.OK).send();
};
res.status(StatusCodes.OK).send()
}
const deleteCrm = async (req, res) => {
@ -191,10 +192,10 @@ const callJournaling = async (req, res) => {
// return res.status(StatusCodes.OK).send()
// Refactor this in the future. Integração Gradezco colombia, o crm sap precisa criar o contato com o + no inicio seguido do codigo do pais
if(companyId == "4953"){ // companyId da gradezco colombia
if (companyId == "4953") { // companyId da gradezco colombia
crmPhone = '57' + crmPhone
}
else{
else {
crmPhone = '55' + crmPhone
}
@ -223,8 +224,6 @@ const callJournaling = async (req, res) => {
// throw new CustomError.BadRequestError(`The crmCallDuration property must be provided when operation is outboundAsweredCall`)
if (!crmCallDuration || crmCallDuration.trim() == "" || crmCallDuration == "0")
crmCallDuration = "10"
@ -232,8 +231,11 @@ const callJournaling = async (req, res) => {
console.log("=======================> crmLastName: ", crmLastName)
// crmLastName
if (operationStatus == "hangup")
await journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration, crmFirstName, crmLastName)
if (operationStatus == "hangup") {
let resp = await journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration, crmFirstName, crmLastName)
return res.status(StatusCodes.OK).json({ ticketLinks: resp })
}
else if (operationStatus == "update-answer") {
@ -269,9 +271,45 @@ const callJournaling = async (req, res) => {
}
const ticketLink = async (req, res) => {
const { companyId, ticketId } = req.query
const crmFiles = await loadCRM(companyId)
const crmContactIds = []
for (const crmConfig of crmFiles) {
const { crmRest: rest, authentication } = crmConfig.crm
let redirectLink = findProperty(rest, 'redirectLink2')
if (redirectLink) {
const url = redirectLink?.request?.url?.replace("crmTicketId", generateC4CServiceRequestDeepLinkBase64(ticketId))
console.log('===============> ticketLink redirect Link: ', url)
return res.status(StatusCodes.OK).json({ link: url })
}
}
res.status(StatusCodes.NOT_FOUND).json({ message: "Company id not found or not exist redirectLink2 property in template crm" })
}
const contactLink = async (req, res) => {
const { companyId, contactId } = req.query
// test start
// return res.status(StatusCodes.OK).json({
// "link": "https://my365398.crm.ondemand.com/sap/ap/ui/clogin?saml2=disabled&app.component=%2fSAP_UI_CT%2fMain%2froot.uiccwoc&rootWindow=X&redirectUrl=%2fsap%2fpublic%2fbyd%2fruntime&supressAutoLogon=true&sap-ui-language=en_us#Nav/1/eyJ0aGluZ3BhcmFtcyI6eyJLZXkiOiJPYm5LZXkkPD94bWwgdmVyc2lvbj1cIjEuMFwiIGVuY29kaW5nPVwidXRmLTE2XCI/PjxPYm5LZXk+PFNvdXJjZT48U291cmNlUGF0aD4vQllEX0NPRC9TZXJ2aWNlT25EZW1hbmQvUHJpdmF0ZUFjY291bnQvQ09EX1NFT0RfSU5EX0FDQ09VTlRfVEkuVEkudWljb21wb25lbnQ8L1NvdXJjZVBhdGg+PC9Tb3VyY2U+PFBhdGg+L1Jvb3QvVGlja2V0TGlzdFswMkMyQUM2NEFDRUMxRkQwQUJCREE2RTAwQTQ0MDQzN10vVVVJRDwvUGF0aD48RGF0YT48VVVJRD4wMkMyQUM2NEFDRUMxRkQwQUJCREE2RTAwQTQ0MDQzNzwvVVVJRD48L0RhdGE+PC9PYm5LZXk+IiwiU291cmNlUGF0aCI6Ii9Sb290L1RpY2tldExpc3RbMDJDMkFDNjRBQ0VDMUZEMEFCQkRBNkUwMEE0NDA0MzddL1VVSUQifSwiaW5Qb3J0IjoiSW5zcGVjdCIsInRhcmdldCI6Ii9CWURfQ09EL1NlcnZpY2VPbkRlbWFuZC9Db2xsYWJvcmF0aW9uL0NPRF9TUl9USS5USS51aWNvbXBvbmVudCIsIndpbklkIjoiYzE1YTIyOWY4ZmQwNGFmNmI0YTJlOTFjYTNlMGZkM2MifQ=="
// })
// test end
const crmFiles = await loadCRM(companyId)
const crmContactIds = []
@ -289,7 +327,7 @@ const contactLink = async (req, res) => {
console.log('===============> Contact id redirect Link: ', url)
return res.status(StatusCodes.OK).json({ link: url});
return res.status(StatusCodes.OK).json({ link: url })
// console.log('new URL(url).hostname: ', new URL(url).hostname)
@ -299,7 +337,7 @@ const contactLink = async (req, res) => {
}
res.status(StatusCodes.NOT_FOUND).json({ message: "Company id not found!"});
res.status(StatusCodes.NOT_FOUND).json({ message: "Company id not found!" })
}
@ -534,6 +572,7 @@ const createTicket = async (req, res) => {
.catch(function (error) {
console.error(`Error on create ticket: companyID ${companyId} | crmPhone: ${crmPhone}`)
console.error(error)
console.error(error?.response?.data)
console.error(error?.response?.status)
console.error(error?.response?.headers)
@ -694,21 +733,21 @@ const webhook_crm = async (req, res) => {
const getClientAccessToken = async (req, res) => {
const { companyId } = req.params
const { clientId } = req.query
console.log('========> getClientAccessToken companyId: ', companyId, ' clientId: ', clientId);
console.log('========> getClientAccessToken companyId: ', companyId, ' clientId: ', clientId)
if (!companyId || !clientId) {
console.error('Company ID or Client ID is missing in the request parameters.');
return res.status(StatusCodes.BAD_REQUEST).send({ msg: "Company ID and Client ID are required!" });
console.error('Company ID or Client ID is missing in the request parameters.')
return res.status(StatusCodes.BAD_REQUEST).send({ msg: "Company ID and Client ID are required!" })
}
const accessToken = await getAccessToken(clientId, companyId);
const accessToken = await getAccessToken(clientId, companyId)
if (!accessToken) {
console.error(`Access token not found for companyId: ${companyId} and clientId: ${clientId}`);
return res.status(StatusCodes.NOT_FOUND).send({ msg: "Access token not found!" });
console.error(`Access token not found for companyId: ${companyId} and clientId: ${clientId}`)
return res.status(StatusCodes.NOT_FOUND).send({ msg: "Access token not found!" })
}
return res.status(StatusCodes.OK).json({ accessToken });
return res.status(StatusCodes.OK).json({ accessToken })
}
module.exports = {
@ -729,7 +768,8 @@ module.exports = {
checkContact,
contactActivity,
getClientAccessToken,
contactLink
contactLink,
ticketLink
}

View File

@ -77,22 +77,43 @@ const CRMRestSchema = new Schema({
body: Object,
response: Object
},
createContactRecord2: {
request: RequestSchema,
body: Object,
response: Object
},
lookupContactByPhone: {
request: RequestSchema,
response: Object
},
lookupContactByPhone2: {
request: RequestSchema,
response: Object
},
createTicketRecord: {
request: RequestSchema,
body: Object,
response: Object
},
createTicketRecord2: {
request: RequestSchema,
body: Object,
response: Object
},
lookupTicket: {
request: RequestSchema,
response: Object
},
lookupTicket2: {
request: RequestSchema,
response: Object
},
redirectLink: {
request: RedirectUrlSchema
},
redirectLink2: {
request: RedirectUrlSchema
},
callJournaling: CallJournalingSchema,
chatJournaling: ChatJournalingSchema,
createCase: {

View File

@ -16,6 +16,9 @@ const crmTicketSchema = new Schema({
type: String,
required: true,
},
ticketId2: {
type: String,
},
contact: {
type: mongoose.Schema.ObjectId,
ref: 'contact',

View File

@ -1,7 +1,7 @@
const express = require('express')
const router = express.Router()
const { authorization, } = require('../middleware/authentication')
const { contactCreate, contactActivity, checkContact, sfCreateCase, sfUpdateCase, createTicket, testTemplate, webhook_crm, uploadCrmConfig, callJournaling, oauthCallBack, install, deleteCrm, deleteCompany, getCrms, webhook, getClientAccessToken, contactLink } = require('../controllers/crmController')
const { contactCreate, contactActivity, checkContact, sfCreateCase, sfUpdateCase, createTicket, testTemplate, webhook_crm, uploadCrmConfig, callJournaling, oauthCallBack, install, deleteCrm, deleteCompany, getCrms, webhook, getClientAccessToken, contactLink, ticketLink } = require('../controllers/crmController')
const { fileUpload } = require("../utils")
router.route('/create-contact').post(authorization, contactCreate)
@ -19,6 +19,7 @@ router.route('/salesforce/case').patch(authorization, sfUpdateCase)
router.route('/oauth-callback').get(oauthCallBack)
router.route('/contact-link').get(authorization, contactLink)
router.route('/ticket-link').get(authorization, ticketLink)
router.route('/install').get(install)
router.route('/test').post(testTemplate)

View File

@ -8,13 +8,27 @@ const CRM = require('../models/CRM')
const requestConfigHeader = require('./requestConfigHeader')
const sendMessageSocket = require('./sendMessageSocket')
async function createContact(companyId, rest, authentication, crmPhone = '', crmFirstName = 'Username', crmLastName = 'Last name', crmEmail = '', test = {}, dynamicBodyRequest = {}) {
let { request, body, response } = findProperty(rest, 'createContactRecord')
async function createContact(companyId, rest, authentication, crmPhone = '', crmFirstName = 'Username', crmLastName = 'Last name', crmEmail = '', test = {}, dynamicBodyRequest = {}, flow = 1) {
let propertyKey
switch (flow) {
case 2:
propertyKey = 'createContactRecord2'
break
default:
propertyKey = 'createContactRecord'
break
}
console.log("===============> createContact propertyKey: ", propertyKey)
let { request, body, response } = findProperty(rest, propertyKey)
const { requestContentType, requestEncoding, requestType, responseType, url } = request
// O identificador a ser usado na requisição (prioriza telefone, mas usa e-mail se não houver)
const lookupValue = crmPhone || crmEmail;
const lookupValue = crmPhone || crmEmail
body = flatten(body)
@ -28,7 +42,7 @@ async function createContact(companyId, rest, authentication, crmPhone = '', crm
for (const prop in body) {
// Para o crm SAP que precisa do +57 no inicio do contato para ser criado corretamente
if(body[prop].includes("+crmPhone")){
if (body[prop].includes("+crmPhone")) {
body[prop] = `+${crmPhone}`
continue
}
@ -95,8 +109,6 @@ async function createContact(companyId, rest, authentication, crmPhone = '', crm
throw error
}
// let { data } = await axios(config)
data = flatten(data)
let auxContactId
@ -117,14 +129,14 @@ async function createContact(companyId, rest, authentication, crmPhone = '', crm
console.log('---------> createContact crmPhone: ', crmPhone, ' | auxContactId: ', auxContactId, ' | auxContactId2: ', auxContactId2)
if (auxContactId && !test?.testing && crmEmail=='') {
if (auxContactId && !test?.testing && crmEmail == '') {
const crm = await CRM.findOne({ companyId, crmBaseURL: new URL(url).hostname })
// await CRM_Contact.create({ companyId, crm, crmBaseURL: new URL(url).hostname, contactId: auxContactId, phone: crmPhone })
await CRM_Contact.create({ companyId, crm, crmBaseURL: new URL(url).hostname, contactId: auxContactId, phone: crmPhone })
}
return { exist: true, contactId: auxContactId, phone: crmPhone, contactId2: auxContactId2}
return { exist: true, contactId: auxContactId, phone: crmPhone, contactId2: auxContactId2, flow: flow }
}

View File

@ -8,18 +8,39 @@ const findProperty = require('./findProperty')
const CRM = require('../models/CRM')
const requestConfigHeader = require('./requestConfigHeader')
const sendEventTicketCreatedToSocket = require('./sendEventTicketCreatedToSocket')
const generateC4CServiceRequestDeepLinkBase64 = require('./generateC4CServiceRequestDeepLinkBase64')
async function createTicket(companyId, rest, authentication, crmPhone, crmFirstName = 'Username', crmLastName = 'Last name', crmEmail = '', test = {}, crmContactId, crmAgent) {
async function createTicket(companyId, rest, authentication, crmPhone, crmFirstName = 'Username', crmLastName = 'Last name', crmEmail = '', test = {}, contact, crmAgent) {
let ticketUrl = ''
let { request, body, response } = findProperty(rest, 'createTicketRecord')
let crmContactId = contact.contactId
let flow = contact?.flow
let propertyKey
switch (flow) {
case 2:
propertyKey = 'createTicketRecord2'
break
default:
propertyKey = 'createTicketRecord'
break
}
console.log('==============> propertyKey createTicketRecord2: ', propertyKey)
let { request, body, response } = findProperty(rest, propertyKey)
console.log('==============> crmContactId: ', crmContactId)
console.log('==============> crmPhone: ', crmPhone)
console.log("==============> contact?.flow: ", contact?.flow)
const { requestContentType, requestEncoding, requestType, responseType, url } = request
console.log('========> body1: ', JSON.stringify(body, null, 6))
console.log("==========>createTicket contact: ", JSON.stringify(contact, null, 6))
body = flatten(body)
@ -30,7 +51,8 @@ async function createTicket(companyId, rest, authentication, crmPhone, crmFirstN
crmLastName,
crmPhone,
crmEmail,
crmContactId
crmContactId,
crmAccountId: contact?.accountId
}
for (const prop in body) {
@ -62,11 +84,7 @@ async function createTicket(companyId, rest, authentication, crmPhone, crmFirstN
sendMessageSocket({ companyId, status: 'processing', data: { request: config, msg } })
}
// console.log('===============> createTicket: ', JSON.stringify(config, null, 6))
console.log('===============> createTicket: ', JSON.stringify(config, null, 6))
let resp
@ -100,6 +118,8 @@ async function createTicket(companyId, rest, authentication, crmPhone, crmFirstN
data = flatten(data)
let auxTicketId
let auxTicketId2
for (const prop in data) {
@ -107,24 +127,40 @@ async function createTicket(companyId, rest, authentication, crmPhone, crmFirstN
if (_prop == response?.id?.trim()) {
auxTicketId = data[prop]
break
}
if (_prop == response?.objectId?.trim()) {
auxTicketId2 = data[prop]
}
}
console.log("========> createTicket auxTicketId: ", auxTicketId, " | auxTicketId2: ", auxTicketId2)
if (auxTicketId && !test?.testing) {
const contact = await CRM_Contact.findOne({ companyId, crmBaseURL: new URL(url).hostname, phone: crmPhone })
let contact2 = await CRM_Contact.findOne({ companyId, crmBaseURL: new URL(url).hostname, phone: crmPhone })
if (!contact2) {
const crm = await CRM.findOne({ companyId, crmBaseURL: new URL(url).hostname })
contact2 = await CRM_Contact.create({ companyId, crm, crmBaseURL: new URL(url).hostname, contactId: contact.contactId, phone: crmPhone })
}
const crm = await CRM.findOne({ companyId, crmBaseURL: new URL(url).hostname })
await CRM_Ticket.create({ companyId, contact, ticketId: auxTicketId, crm })
await CRM_Ticket.create({ companyId, contact: contact2, ticketId: auxTicketId, ticketId2: auxTicketId2, crm })
// ticketUrl = `https://app.hubspot.com/contacts/23636141/ticket/${auxTicketId}`
if (url.includes("hubapi")) {
ticketUrl = `https://app.hubspot.com/contacts/${crmAccountId}/ticket/${auxTicketId}`
}
else if (url.includes("c4codataapi")) {
ticketUrl = `https://my365398.crm.ondemand.com/sap/ap/ui/clogin?saml2=disabled&app.component=%2fSAP_UI_CT%2fMain%2froot.uiccwoc&rootWindow=X&redirectUrl=%2fsap%2fpublic%2fbyd%2fruntime&supressAutoLogon=true&sap-ui-language=en_us#Nav/1/${generateC4CServiceRequestDeepLinkBase64(auxTicketId2)}`
}
sendEventTicketCreatedToSocket({ companyId, extension: crmAgent, ticketUrl: ticketUrl })
}
return { exist: true, ticketId: auxTicketId, phone: crmPhone, ticketUrl }
return { exist: true, ticketId: auxTicketId, ticketId2: auxTicketId2, phone: crmPhone, ticketUrl }
}

View File

@ -0,0 +1,34 @@
function generateC4CServiceRequestDeepLinkBase64(objectId) {
// 1. Defina o XML Template.
// O UUID deve ser inserido duas vezes neste XML.
const xmlTemplate = `<?xml version="1.0" encoding="utf-16"?><ObnKey><Source><SourcePath>/BYD_COD/SalesOnDemand/Account/UI/COD_Account_TI.TI.uicomponent</SourcePath></Source><Path>/Root/ServiceRequests[${objectId}]/UUID</Path><Data><UUID>${objectId}</UUID></Data></ObnKey>`
// 2. Defina o objeto JSON completo (Payload).
const payload = {
"thingparams": {
// O XML deve ser incluído dentro da string 'Key' e escapar as aspas.
"Key": `ObnKey$${xmlTemplate.replace(/"/g, '\\"')}`,
"SourcePath": `/Root/ServiceRequests[${objectId}]/UUID`
},
"inPort": "Inspect",
"target": "/BYD_COD/ServiceOnDemand/Collaboration/COD_SR_TI.TI.uicomponent",
// Note: O 'winId' é geralmente fixo ou pode ser dinâmico em algumas implementações.
// Estamos usando o valor que você forneceu:
"winId": "b175025e290bfa7a7b5a8c88c3330546"
}
// 3. Converta o objeto JSON para uma string JSON (sem formatação).
const jsonString = JSON.stringify(payload)
// 4. Codifique a string JSON para Base64.
// Node.js utiliza Buffer.from(string).toString('base64').
const base64String = Buffer.from(jsonString, 'utf8').toString('base64')
return base64String
}
module.exports = generateC4CServiceRequestDeepLinkBase64

View File

@ -4,10 +4,12 @@ const createContact = require('./createContact')
const findProperty = require('./findProperty')
const journalingRequest = require('./journalingRequest')
const ticketCRM = require('./ticketCRM')
async function journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration = 0, crmFirstName ='Username', crmLastName = 'Last name') {
async function journaling(companyId, operation, crmPhone, crmAgent, crmCallDuration = 0, crmFirstName = 'Username', crmLastName = 'Last name') {
const crmFiles = await loadCRM(companyId)
const crmTicketLinks = []
for (const crmConfig of crmFiles) {
@ -15,8 +17,11 @@ async function journaling(companyId, operation, crmPhone, crmAgent, crmCallDurat
let contact = await lookupContactByPhone(rest, authentication, crmPhone, companyId)
console.log("===========> journaling contat ", JSON.stringify(contact, null, 6))
if (!contact.exist) {
contact = await createContact(companyId, rest, authentication, crmPhone, crmFirstName, crmLastName)
// createContact(companyId, rest, authentication, crmPhone = '', crmFirstName = 'Username', crmLastName = 'Last name', crmEmail = '', test = {}, dynamicBodyRequest = {})
contact = await createContact(companyId, rest, authentication, crmPhone, crmFirstName, crmLastName, crmEmail = '', test = {}, dynamicBodyRequest = {}, contact?.flow)
}
let { request, calls, response } = findProperty(rest, 'callJournaling')
@ -25,6 +30,29 @@ async function journaling(companyId, operation, crmPhone, crmAgent, crmCallDurat
await journalingRequest(request, body, crmCallDuration, contact, crmAgent, crmPhone, authentication, rest, companyId)
// create ticket crm sap cliente gradezco. To each call is created or open a ticket
if (companyId == "4953") {
console.log("============> journaling contact?.flow: ", contact?.flow)
const crmTicketLinks = await ticketCRM(companyId, crmPhone, crmAgent, crmFirstName, contact?.flow)
.catch(function (error) {
console.error(`Error on create jounaling ticket: companyID ${companyId} | crmPhone: ${crmPhone}`)
console.error(error)
console.error(error?.response?.data)
console.error(error?.response?.status)
console.error(error?.response?.headers)
throw new Error(`Error on create jounaling ticket: companyID ${companyId} | crmPhone: ${crmPhone}`)
})
// console.log('jounaling crmTicketLinks: ', crmTicketLinks)
return crmTicketLinks
}
return []
}
}

View File

@ -17,7 +17,7 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
let { requestContentType, requestEncoding, requestType, responseType, url } = request
const { type, userName, passWord, token, crmClientId, crmAccountId} = authentication
const { type, userName, passWord, token, crmClientId, crmAccountId } = authentication
if (cacheContact) {
const crmInfo = await CRM_Contact.findOne({ companyId, crmBaseURL: new URL(url).hostname, phone: crmPhone })
@ -35,10 +35,10 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
console.log("PAYLOAD CONFIG LOOKUP CONTACT BY PHONE CONFIG.url 1: ", config.url)
// Para consultar contato crm SAP, necessário consultar sem sinal de + no inicio numero
const pattern = /%2B\+/g;
const pattern = /%2B\+/g
if (pattern.test(config.url)){
config.url = config.url.replace(/%2B\+/g, '%2B');
if (pattern.test(config.url)) {
config.url = config.url.replace(/%2B\+/g, '%2B')
}
console.log("PAYLOAD CONFIG LOOKUP CONTACT BY PHONE CONFIG.url 2: ", config.url)
@ -50,6 +50,36 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
try {
let { data: _data } = await axios(config)
data = _data
const contactExists = JSON.stringify(data)?.includes(crmPhone)
console.log("=========> contactExists: ", contactExists)
console.log("=========> data 1: ", JSON.stringify(data, null, 6))
const lookupContactByPhone2 = findProperty(rest, 'lookupContactByPhone2')
if (lookupContactByPhone2?.request?.url && !contactExists) {
const { request: request2, response: response2 } = lookupContactByPhone2
const { url } = request2
config.url = url.replace("crmPhone", crmPhone)
console.log("==========> lookupContactByPhone2 url: ", url)
console.log("==========> lookupContactByPhone2 config: ", JSON.stringify(config, null, 6))
let { data: _data2 } = await axios(config)
data = _data2
data.flow = 2
if (response2) {
response = response2
}
console.log("=========> data 2: ", JSON.stringify(data, null, 6))
}
} catch (error) {
if (error.response) {
console.error('==================> lookupContactByPhone Erro na resposta da API:', {
@ -106,8 +136,6 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
}
data = flatten(data)
let auxPhone
@ -138,13 +166,12 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
console.log('===========> !auxPhone && !auxContactId: ', !auxPhone && !auxContactId)
if (!auxPhone && !auxContactId) {
for (const prop in data) {
let _prop = prop.replace(/\.(\d+)(\.|$)/g, '[$1]$2')
// console.log("_prop: ", _prop, " | response ", JSON.stringify(response, null, 6))
// console.log("\n_prop: ", _prop, "\n| response: ", JSON.stringify(response, null, 6), "\n| data[prop]: ", data[prop], "\n| _prop: ", _prop)
// SALESFORCE GETTING THE NAME
if (_prop == response?.name?.trim()) {
@ -175,10 +202,12 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
}
}
console.log("=========> auxAccountId from contact response: ", auxAccountId)
// Tenta pegar o accountId no body da resposta se não conseguir, pega do template se a propriedade crmAccountId existir no template
// Foi criado dessa forma para evitar problemas com integrações que já estão em funcionamento
if(!auxAccountId && crmAccountId){
console.log('---------> auxAccountId definido a partir do crmAccountId do template: ',crmAccountId)
if (!auxAccountId && crmAccountId) {
console.log('---------> auxAccountId definido a partir do crmAccountId do template: ', crmAccountId)
auxAccountId = crmAccountId
}
@ -218,18 +247,14 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
console.log('----------------> CREATE CONTACT MONGO')
const crm = await CRM.findOne({ companyId, crmBaseURL: new URL(url).hostname })
await CRM_Contact.create({ companyId, crm, crmBaseURL: new URL(url).hostname, contactId: auxContactId, phone: auxPhone })
}
}
return { exist: true, contactId: auxContactId, phone: crmPhone, name: auxName, accountId: auxAccountId, contactId2: auxContactId2}
return { exist: true, contactId: auxContactId, phone: crmPhone, name: auxName, accountId: auxAccountId, contactId2: auxContactId2, flow: data?.flow }
}
return { exist: false }
return { exist: false, flow: data?.flow }
}
module.exports = lookupContactByPhone

View File

@ -17,9 +17,23 @@ const findTicketOpenHubspotByContact = require('./findTicketOpenHubspotByContact
const lookupContactByPhone = require('./lookupCRMContactByPhone')
async function lookupCrmTicket(rest, authentication, crmPhone, companyId, test = {}, ticketId) {
async function lookupCrmTicket(rest, authentication, crmPhone, companyId, test = {}, ticketId, contact = null) {
let { request, body, response } = findProperty(rest, 'lookupTicket')
let flow = contact?.flow
let propertyKey
switch (flow) {
case 2:
propertyKey = 'lookupTicket2'
break
default:
propertyKey = 'lookupTicket'
break
}
let { request, body, response } = findProperty(rest, propertyKey)
let { requestContentType, requestEncoding, requestType, responseType, url } = request
@ -33,6 +47,51 @@ async function lookupCrmTicket(rest, authentication, crmPhone, companyId, test =
sendMessageSocket({ companyId, status: 'processing', data: { request: config, msg } })
}
// Para crm sap
if (url.includes("crmContactId") && contact && url.includes("c4codataapi")) {
// Valor do contato
const contactId = contact.contactId // Ex: "1112048"
console.log("============> entrou no if crmContactId: ", contactId)
// 1. O valor OData correto, com aspas simples, DEVE SER: '1112048'
const odataValueWithQuotes = `'${contactId}'`
// 2. Codificação URL do valor OData: '%271112048%27'
const correctEncodedValue = encodeURIComponent(odataValueWithQuotes)
// 3. Substitua a string incorreta (que contém o '%' extra e as aspas incorretas) pela correta.
// O template parece ser: ...eq%20%crmContactId%27
const templateToReplace = `%${'crmContactId'}%27`
// A string FINAL no URL deve ser: ...eq%20%271112048%27
// Tentativa de correção: Substitua a string inteira que contém o placeholder errado pela correta
// ATENÇÃO: Se o contactId for '1112048', o template incorreto que está no config.url é:
// `%1112048%27` (depois de rodar a primeira substituição)
// OU `%crmContactId%27` (se a substituição ainda não ocorreu)
// Vamos substituir a string do template ANTES de qualquer coisa.
// Usaremos 'crmContactId' como marcador de substituição:
config.url = config.url.replace(
// String que está incorreta no seu template (que gera o erro): "%crmContactId%27"
`%${'crmContactId'}%27`,
// String correta que o servidor OData espera (Aspas codificadas corretamente): "%27" + <contactId> + "%27"
correctEncodedValue
)
}
if (url.includes("crmContactId") && contact && url.includes("c4codataapi")) {
config.url = config.url.replace('crmContactId', contact.contactId)
}
console.log("============ journaling contact: ", JSON.stringify(contact, null, 6))
console.log("PAYLOAD CONFIG LOOKUP TICKET BY PHONE: ", JSON.stringify(config, null, 6))
let resp
try {
@ -46,7 +105,7 @@ async function lookupCrmTicket(rest, authentication, crmPhone, companyId, test =
if (error.response) {
console.error('==================> lookupCrmTicket Erro na resposta da API:', {
status: error.response.status,
data: error.response.data,
data: JSON.stringify(error.response.data, null, 6),
})
}
else if (error.request) {
@ -66,6 +125,8 @@ async function lookupCrmTicket(rest, authentication, crmPhone, companyId, test =
let auxTicketStatus
let auxTicketId
let auxTicketId2
for (const prop in data) {
@ -79,7 +140,11 @@ async function lookupCrmTicket(rest, authentication, crmPhone, companyId, test =
auxTicketId = data[prop]
}
if (auxTicketStatus && auxTicketId) break
if (_prop == response?.objectId?.trim()) {
auxTicketId2 = data[prop]
}
// if (auxTicketStatus && auxTicketId) break
}
@ -96,12 +161,16 @@ async function lookupCrmTicket(rest, authentication, crmPhone, companyId, test =
auxTicketId = data[prop]
}
if (auxTicketStatus && auxTicketId) break
if (_prop == response?.objectId?.trim()) {
auxTicketId2 = data[prop]
}
// if (auxTicketStatus && auxTicketId) break
}
}
console.log(`[${new Date()}] auxTicketStatus: ${auxTicketStatus} | auxTicketId: ${auxTicketId}`)
console.log(`[${new Date()}] auxTicketStatus: ${auxTicketStatus} | auxTicketId: ${auxTicketId} | auxTicketId2: ${auxTicketId2}`)
if (url.includes('api.hubapi.com')) {
@ -121,8 +190,16 @@ async function lookupCrmTicket(rest, authentication, crmPhone, companyId, test =
return { auxTicketId, auxTicketStatus }
}
// To sap crm, consdering status open == 1
else if (url.includes("c4codataapi")) {
if (auxTicketStatus && auxTicketStatus.toLowerCase() == "open")
auxTicketStatus = 1
else
auxTicketStatus = 0
}
return { auxTicketId, auxTicketStatus }
return { auxTicketId, auxTicketStatus, auxTicketId2 }
}

View File

@ -5,7 +5,6 @@ const findProperty = require('./findProperty')
const CRM_Contact = require('../models/CRM_Contact')
const CRM_Ticket = require('../models/CRM_Ticket')
const CRM = require('../models/CRM')
const createTicket = require('./createTicket')
const lookupCRMTicket = require('./lookupCRMTicket')
const sendEventTicketCreatedToSocket = require('./sendEventTicketCreatedToSocket')

View File

@ -16,8 +16,9 @@ const getHubspotPipelines = require('./getHubspotPipelines')
const mongoose = require('mongoose')
const getHubspotTicketStatusByContact = require('./getHubspotTicketStatusByContact')
const findTicketOpenHubspotByContact = require('./findTicketOpenHubspotByContact')
const generateC4CServiceRequestDeepLinkBase64 = require('./generateC4CServiceRequestDeepLinkBase64')
async function ticketCRM(companyId, crmPhone, crmAgent = "0000", crmFirstName = 'Username') {
async function ticketCRM(companyId, crmPhone, crmAgent = "0000", crmFirstName = 'Username', flow = 1) {
const crmFiles = await loadCRM(companyId)
@ -28,38 +29,63 @@ async function ticketCRM(companyId, crmPhone, crmAgent = "0000", crmFirstName =
const { crmRest: rest, authentication } = crmConfig.crm
// Send the ticket url link to hitphone to open on another browser tab
let obj = findProperty(rest, 'lookupTicket')
let propertyKey
switch (flow) {
case 2:
propertyKey = 'lookupTicket2'
break
default:
propertyKey = 'lookupTicket'
break
}
// find ticket
let obj = findProperty(rest, propertyKey)
let ticket_id = ''
let ticket_id2 = ''
let ticket_url = ''
let isCreated = false
console.log("===========> ticketCRM obj: ", obj)
if (obj) {
const { crmAccountId } = authentication
console.log("------------> ticketCRM crmAccountId: ",crmAccountId)
console.log("------------> ticketCRM crmAccountId: ", crmAccountId)
let { url } = obj.request
console.log("------------> ticketCRM url: ", url)
let contact = await _lookupContact(rest, authentication, crmPhone, companyId, crmFirstName, url)
console.log("------------> ticketCRM contact: ", JSON.stringify(contact, null, 6))
const crm = await CRM.findOne({
companyId, crmBaseURL: new URL(url.trim()).hostname
})
const obj_contact = await CRM_Contact.findOne({ companyId, crmBaseURL: new URL(url).hostname, phone: crmPhone })
console.log("------------> ticketCRM obj_contact: ", JSON.stringify(obj_contact, null, 6))
const obj_ticket = await CRM_Ticket.findOne(
{ companyId, crm, contact: obj_contact }
).select('ticketId')
).select('ticketId ticketId2')
console.log("------------> ticketCRM obj_ticket: ", JSON.stringify(obj_ticket, null, 6))
if (obj_ticket) {
const { ticketId } = obj_ticket
const { ticketId, ticketId2 } = obj_ticket
if (ticketId) {
ticket_id = ticketId
}
if (ticketId2) {
ticket_id2 = ticketId2
}
const obj_ticket_status = await lookupCRMTicket(
rest,
@ -67,15 +93,19 @@ async function ticketCRM(companyId, crmPhone, crmAgent = "0000", crmFirstName =
crmPhone,
companyId,
test = { testing: false },
obj_ticket.ticketId
obj_ticket.ticketId,
contact
)
if (obj_ticket_status)
console.log("obj_ticket_status: ", JSON.stringify(obj_ticket_status, null, 6))
if (obj_ticket_status) {
const { auxTicketStatus, error } = obj_ticket_status
console.log("===============> ticketCRM url: ", url, " | error: ", error, " | auxTicketStatus: ", auxTicketStatus)
// refactor this for production. For now only working with hubspot where status new is equal 1
if ((auxTicketStatus && auxTicketStatus != '1') || (error && error == 404)) {
@ -105,9 +135,10 @@ async function ticketCRM(companyId, crmPhone, crmAgent = "0000", crmFirstName =
}
const { ticketUrl, ticketId } = await _createTicket(rest, crmPhone, companyId, authentication, crmFirstName, contact, crmAgent)
const { ticketUrl, ticketId, ticketId2 } = await _createTicket(rest, crmPhone, companyId, authentication, crmFirstName, contact, crmAgent, flow)
ticket_id = ticketId
ticket_id2 = ticketId2
isCreated = true
// crmTicketLinks.push({ ticketUrl, ticketId })
@ -117,7 +148,6 @@ async function ticketCRM(companyId, crmPhone, crmAgent = "0000", crmFirstName =
}
else {
if (url.includes("hubapi")) {
console.log(`[${new Date()}] ****** IS HUBSPOT CRM LETS TRY FINDING AN OPEN TICKET TO THE CONTACT****** `)
@ -141,20 +171,77 @@ async function ticketCRM(companyId, crmPhone, crmAgent = "0000", crmFirstName =
continue
}
}
// To sap crm try to find ticket open
else if (url.includes("c4codataapi")) {
const result = await lookupCRMTicket(
rest,
authentication,
crmPhone,
companyId,
test = { testing: false },
obj_ticket?.ticketId,
contact
)
// elefante
const { auxTicketId, auxTicketStatus, auxTicketId2 } = result
console.log("============> TICKET STATUS: ", auxTicketStatus, " | auxTicketId: ", auxTicketId)
if (auxTicketStatus == 1 && auxTicketId2) {
ticket_id = auxTicketId
ticket_id2 = auxTicketId2
isCreated = false
const _ticketUrl = `https://my365398.crm.ondemand.com/sap/ap/ui/clogin?saml2=disabled&app.component=%2fSAP_UI_CT%2fMain%2froot.uiccwoc&rootWindow=X&redirectUrl=%2fsap%2fpublic%2fbyd%2fruntime&supressAutoLogon=true&sap-ui-language=en_us#Nav/1/${generateC4CServiceRequestDeepLinkBase64(auxTicketId2)}`
crmTicketLinks.push({
ticketId: auxTicketId2,
ticketUrl: _ticketUrl,
created: isCreated,
})
// sinc ticket
let __contact = await CRM_Contact.findOne({ companyId, crmBaseURL: new URL(url).hostname, phone: crmPhone })
await CRM_Ticket.deleteMany({ companyId, contact: __contact })
const crm = await CRM.findOne({ companyId, crmBaseURL: new URL(url).hostname })
await CRM_Ticket.create({ companyId, contact: __contact, ticketId: auxTicketId, ticketId2: auxTicketId2, crm })
continue
}
}
console.log(`[${new Date()}] ****** CREATE TICKET ****** `)
const { ticketUrl, ticketId } = await _createTicket(rest, crmPhone, companyId, authentication, crmFirstName, contact, crmAgent)
const { ticketUrl, ticketId, ticketId2 } = await _createTicket(rest, crmPhone, companyId, authentication, crmFirstName, contact, crmAgent, flow)
ticket_id = ticketId
ticket_id2 = ticketId2
// ticket_url = ticketUrl
isCreated = true
}
if (url.includes("hubapi")) {
crmTicketLinks.push({
ticketId: `https://app.hubspot.com/contacts/${crmAccountId}/ticket/${ticket_id}`,
created: isCreated,
})
}
// To sap crm
else if (url.includes("c4codataapi")) {
console.log("=================> c4codataapi ticket_id2: ", ticket_id2)
crmTicketLinks.push({
ticketId: ticket_id2,
ticketUrl: `https://my365398.crm.ondemand.com/sap/ap/ui/clogin?saml2=disabled&app.component=%2fSAP_UI_CT%2fMain%2froot.uiccwoc&rootWindow=X&redirectUrl=%2fsap%2fpublic%2fbyd%2fruntime&supressAutoLogon=true&sap-ui-language=en_us#Nav/1/${generateC4CServiceRequestDeepLinkBase64(ticket_id2)}`,
created: isCreated,
})
}
}
//
@ -213,7 +300,7 @@ async function _lookupContact(rest, authentication, crmPhone, companyId, crmFirs
let contact = await lookupContactByPhone(rest, authentication, crmPhone, companyId)
if (contact?.exist) {
return { created: false, contactId: contact.contactId }
return { created: false, contactId: contact.contactId, contactId2: contact.contactId2, accountId: contact?.accountId, flow: contact?.flow }
}
if (!contact?.exist) {
@ -231,11 +318,23 @@ async function _lookupContact(rest, authentication, crmPhone, companyId, crmFirs
contact = await createContact(companyId, rest, authentication, crmPhone, crmFirstName)
}
return { created: true, contactId: contact.contactId }
return { created: true, contactId: contact.contactId, contactId2: contact.contactId2, accountId: contact?.accountId, flow: contact?.flow }
}
async function _createTicket(rest, crmPhone, companyId, authentication, crmFirstName, contact, crmAgent) {
let obj = findProperty(rest, 'createTicketRecord')
async function _createTicket(rest, crmPhone, companyId, authentication, crmFirstName, contact, crmAgent, flow = 1) {
let propertyKey
switch (flow) {
case 2:
propertyKey = 'createTicketRecord2'
break
default:
propertyKey = 'createTicketRecord'
break
}
let obj = findProperty(rest, propertyKey)
let ticket_url = ''
let ticket_id = ''
@ -248,7 +347,7 @@ async function _createTicket(rest, crmPhone, companyId, authentication, crmFirst
// return { exist: true, ticketId: auxTicketId, phone: crmPhone, ticketUrl }
// return { exist: true, ticketId: auxTicketId, phone: crmPhone, ticketUrl }
const { ticketUrl, ticketId, } = await createTicket(companyId,
const { ticketUrl, ticketId, ticketId2 } = await createTicket(companyId,
rest,
authentication,
crmPhone,
@ -256,14 +355,15 @@ async function _createTicket(rest, crmPhone, companyId, authentication, crmFirst
crmLastName = '',
crmEmail = '',
test = { testing: false },
crmContactId = contact.contactId,
contact,
crmAgent
)
ticket_id = ticketId
ticket_id2 = ticketId2
ticket_url = ticketUrl
}
}
return { crmFirstName, ticketUrl: ticket_url, ticketId: ticket_id }
return { crmFirstName, ticketUrl: ticket_url, ticketId: ticket_id, ticketId2: ticket_id2 }
}

View File

@ -6,7 +6,6 @@ const findProperty = require('./findProperty')
const CRM_Contact = require('../models/CRM_Contact')
const CRM_Ticket = require('../models/CRM_Ticket')
const CRM = require('../models/CRM')
const createTicket = require('./createTicket')
const lookupCRMTicket = require('./lookupCRMTicket')
const sendEventTicketCreatedToSocket = require('./sendEventTicketCreatedToSocket')
@ -106,42 +105,46 @@ module.exports = whatsappJournalingCRM
// }
async function _lookupContact(rest, authentication, crmPhone, crmEmail, companyId, crmFirstName) {
let contact = null;
let contact = null
// 1. Tenta buscar o contato por telefone se o crmPhone for fornecido
if (crmPhone) {
console.log(`Buscando contato por telefone: ${crmPhone}`);
contact = await lookupContactByPhone(rest, authentication, crmPhone, companyId);
console.log(`Buscando contato por telefone: ${crmPhone}`)
contact = await lookupContactByPhone(rest, authentication, crmPhone, companyId)
}
// 2. Se não encontrou por telefone, tenta buscar por e-mail se o crmEmail for fornecido
if (!contact?.exist && crmEmail) {
console.log(`Contato não encontrado por telefone. Tentando por e-mail: ${crmEmail}`);
contact = await lookupContactByEmail(rest, authentication, crmEmail, companyId);
console.log(`Contato não encontrado por telefone. Tentando por e-mail: ${crmEmail}`)
contact = await lookupContactByEmail(rest, authentication, crmEmail, companyId)
}
// 3. Se o contato já existe (seja por telefone ou e-mail), retorna as informações
if (contact?.exist) {
console.log(`Contato encontrado! ID: ${contact.contactId}`);
return { created: false, contactId: contact.contactId, contactId2: contact?.contactId2 };
console.log(`Contato encontrado! ID: ${contact.contactId}`)
return { created: false, contactId: contact.contactId, contactId2: contact?.contactId2 }
}
// 4. Se o contato não foi encontrado por nenhuma das formas, cria um novo
console.log(`Contato não encontrado. Criando um novo com base no ${crmPhone ? 'telefone' : 'e-mail'}.`);
console.log(`Contato não encontrado. Criando um novo com base no ${crmPhone ? 'telefone' : 'e-mail'}.`)
// AQUI ESTÁ A ÚNICA MUDANÇA NECESSÁRIA:
// Chamamos createContact passando os valores de telefone e e-mail separadamente.
// A função createContact agora sabe como lidar com ambos, mesmo que um deles seja vazio.
contact = await createContact(companyId, rest, authentication, crmPhone, crmFirstName, 'Last name', crmEmail);
// createContact(companyId, rest, authentication, crmPhone = '', crmFirstName = 'Username', crmLastName = 'Last name', crmEmail = '', test = {}, dynamicBodyRequest = {}, flow = 1)
console.log("=================> whatsappJournalingCRM contact?.flow: ", contact?.flow)
contact = await createContact(companyId, rest, authentication, crmPhone, crmFirstName, 'Last name', crmEmail, test = {}, dynamicBodyRequest = {}, flow = contact?.flow)
// Se o contato for criado, retorna suas informações
if (contact?.contactId) {
console.log(`Novo contato criado com ID: ${contact.contactId}`);
return { created: true, contactId: contact.contactId, contactId2: contact?.contactId2};
console.log(`Novo contato criado com ID: ${contact.contactId}`)
return { created: true, contactId: contact.contactId, contactId2: contact?.contactId2 }
}
// Caso não tenha nem telefone nem e-mail, retorna um erro ou um valor nulo
console.error("Erro: Não foi possível encontrar ou criar um contato. Telefone e e-mail não fornecidos.");
return null;
console.error("Erro: Não foi possível encontrar ou criar um contato. Telefone e e-mail não fornecidos.")
return null
}