Compare commits

...

6 Commits

15 changed files with 310 additions and 92 deletions

90
.gitignore vendored
View File

@ -9,6 +9,96 @@
**/backend/build
**/frontend/dist
# **/frontend/build
/node_modules
# ===============================
# Node / React.js base
# ===============================
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
package-lock.json
yarn.lock
.pnpm-debug.log
# ===============================
# Build output
# ===============================
build/
dist/
.out/
.cache/
.temp/
# ===============================
# Environment variables
# ===============================
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# ===============================
# Logs
# ===============================
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# ===============================
# Editor / IDE
# ===============================
.vscode/
.idea/
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# ===============================
# OS files
# ===============================
.DS_Store
Thumbs.db
# ===============================
# Test coverage / reports
# ===============================
coverage/
*.lcov
# ===============================
# Misc
# ===============================
*.bak
*.tmp
*.old
*.orig
# ===============================
# Local development tools
# ===============================
/.eslintcache
/.stylelintcache
/.parcel-cache
/.next/
.storybook-out/
storybook-static/
# ===============================
# React Native (if any hybrid code)
# ===============================
.expo/
android/
ios/

View File

@ -1,8 +1,8 @@
{
"authentication":{
"type":"oauth2",
"crmClientId":"3MVG9_I_oWkIqLrkzfDaK8hlNFdHqjRWZ62.9A6C8bCCuZsTmzJVokEhC.xFZq8LjH8aacBs8CNb_lQSHcfMw",
"crmClientSecret":"7AEBE0AE0AE6386D34348A7D83D56234CCA1406998DF804F1AD0DE6AB1E55E75",
"crmClientId":"3MVG9R4W1j5vZNbwWpFjySFZCan3YpJziuLJyMuZMja9EYs9LBHGQlRpsjn_EXaZOfuLJpaC2THw6B_cL5PHE",
"crmClientSecret":"95A1B59F22C5A5720A25B0EC72B7B49966DF97D20F28202E7D66C1DB71E93785",
"crmScopes":"full refresh_token",
"crmPhoneTest":"5514983253326",
"crmOAuthRefreshToken":"5Aep861dGfrsDEfsAziKaAP7kJIZ_jtDR9PknPzivGHe39mGzePJXl6LwYfSJGnAe9F_oZ0AalhUk2tdLidlCg_",
@ -190,7 +190,7 @@
"body":{
"Subject":"Caso criado na URA",
"Status":"Aberto",
"ContactId":"0038800000LVXFfAAP",
"ContactId":"crmContactId",
"AccountId":"0018800000fuRajAAE",
"Origin":"Telefone",
"Priority":"Médio",

View File

@ -0,0 +1,106 @@
{
"authentication":{
"type": "basic",
"userName": "_INTEGRACAO_",
"passWord": "p3G44K10366",
"crmPhoneTest":"+5511998765123",
"crmAccountId":"1000320"
},
"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",
"Mobile":"+crmPhone",
"AccountID":"1000320"
},
"response":{
"id":"d.results.ContactID",
"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,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"
}
}
},
{
"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",
"MainAccountPartyID": "1000320",
"MainContactPartyID":"crmContactId"
}
},
{
"outboundAnsweredCall":{
"Subject": "Ligação Realizada",
"Status": "1",
"InitiatorCode": "3",
"DataOriginTypeCode": "3",
"MainAccountPartyID": "1000320",
"MainContactPartyID":"crmContactId"
}
}
]
}
},
{
"chatJournaling":{
"request":{
"requestContentType":"application/json",
"requestEncoding":"Json",
"requestType":"Post",
"responseType":"Json",
"url":"https://my365398.crm.ondemand.com/sap/c4c/odata/v1/c4codataapi/ContactCollection('contactObjectId')/ContactTextCollection"
},
"chats":[
{
"chatDone":{
"Text": "Conversation started via WhatsApp. Conversation link: chatLink"
}
}
]
}
},
{
"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"
}
}
}
]
}

View File

@ -187,13 +187,17 @@ const callJournaling = async (req, res) => {
// Remove 0 from the beginning of the number. Ex: 011996067641 to 11996067641
crmPhone = removeZeroInicial(crmPhone)
// test remove
// return res.status(StatusCodes.OK).send()
// Refactor this in the future.
// 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
crmPhone = '57' + crmPhone
}
else{
crmPhone = '55' + crmPhone
}
console.log('========> CRMPHONE: ', crmPhone)
console.log('========> COMPANY ID before: ', companyId)
@ -264,6 +268,40 @@ const callJournaling = async (req, res) => {
}
const contactLink = async (req, res) => {
const { companyId, contactId } = req.query
const crmFiles = await loadCRM(companyId)
const crmContactIds = []
for (const crmConfig of crmFiles) {
const { crmRest: rest, authentication } = crmConfig.crm
// Send the edited contact/lead link url to hitphone to open on another browser tab
let redirectLink = findProperty(rest, 'redirectLink')
if (redirectLink) {
const url = redirectLink?.request?.url?.replace(/crmContactId/g, contactId)
console.log('===============> Contact id redirect Link: ', url)
return res.status(StatusCodes.OK).json({ link: url});
// console.log('new URL(url).hostname: ', new URL(url).hostname)
// crmContactIds.push({ crm: new URL(url).hostname, contactId })
}
//
}
res.status(StatusCodes.NOT_FOUND).json({ message: "Company id not found!"});
}
const sfCreateCase = async (req, res) => {
@ -689,7 +727,8 @@ module.exports = {
createTicket,
checkContact,
contactActivity,
getClientAccessToken
getClientAccessToken,
contactLink
}

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 } = require('../controllers/crmController')
const { contactCreate, contactActivity, checkContact, sfCreateCase, sfUpdateCase, createTicket, testTemplate, webhook_crm, uploadCrmConfig, callJournaling, oauthCallBack, install, deleteCrm, deleteCompany, getCrms, webhook, getClientAccessToken, contactLink } = require('../controllers/crmController')
const { fileUpload } = require("../utils")
router.route('/create-contact').post(authorization, contactCreate)
@ -17,6 +17,9 @@ router.route('/delete-company').post(authorization, deleteCompany)
router.route('/salesforce/case').post(authorization, sfCreateCase)
router.route('/salesforce/case').patch(authorization, sfUpdateCase)
router.route('/oauth-callback').get(oauthCallBack)
router.route('/contact-link').get(authorization, contactLink)
router.route('/install').get(install)
router.route('/test').post(testTemplate)
router.route('/webhook').post(webhook)

View File

@ -26,8 +26,17 @@ 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")){
body[prop] = `+${crmPhone}`
continue
}
if (mapping.hasOwnProperty(body[prop])) {
const variable = mapping[body[prop]]
if (variable) {
body[prop] = variable
} else {
@ -91,6 +100,7 @@ async function createContact(companyId, rest, authentication, crmPhone = '', crm
data = flatten(data)
let auxContactId
let auxContactId2
for (const prop in data) {
@ -98,10 +108,14 @@ async function createContact(companyId, rest, authentication, crmPhone = '', crm
if (_prop == response?.id?.trim()) {
auxContactId = data[prop]
break
}
if (_prop == response?.objectId?.trim()) {
auxContactId2 = data[prop]
}
}
console.log('---------> createContact crmPhone: ', crmPhone, ' | auxContactId: ', auxContactId, ' | auxContactId2: ', auxContactId2)
if (auxContactId && !test?.testing && crmEmail=='') {
@ -110,7 +124,7 @@ async function createContact(companyId, rest, authentication, crmPhone = '', crm
await CRM_Contact.create({ companyId, crm, crmBaseURL: new URL(url).hostname, contactId: auxContactId, phone: crmPhone })
}
return { exist: true, contactId: auxContactId, phone: crmPhone }
return { exist: true, contactId: auxContactId, phone: crmPhone, contactId2: auxContactId2}
}

View File

@ -8,10 +8,17 @@ const convertToIntegerIfNumber = require('./convertToIntegerIfNumber')
const sendMessageSocket = require('./sendMessageSocket')
// request, body, crmCallDuration, contact, crmAgent, crmPhone, authentication, rest, companyId
async function journalingRequest(request, body, crmCallDuration, contact, crmAgent, crmPhone, authentication, test = {}, companyId = '', dynamicBodyRequest = {}) {
const { requestContentType, requestEncoding, requestType, responseType, url } = request
let { requestContentType, requestEncoding, requestType, responseType, url } = request
console.log('----------> crmCallDuration: ', crmCallDuration)
console.log('----------> url: ', url)
console.log('----------> journalingRequest url 1: ', url)
// Second contactId for some cases like SAP crm that use ObjectID to create note
if(url.includes("contactObjectId") && contact?.contactId2){
url = url.replace("contactObjectId", contact.contactId2)
}
console.log('----------> journalingRequest url 2: ', url)
body = flatten(body)

View File

@ -25,13 +25,24 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
if (crmInfo) return { exist: true, contactId: crmInfo.contactId, phone: crmPhone }
}
const config = await requestConfigHeader(url, crmPhone, requestType, requestContentType, type, userName, passWord, token, crmClientId, '', '', companyId)
let config = await requestConfigHeader(url, crmPhone, requestType, requestContentType, type, userName, passWord, token, crmClientId, '', '', companyId)
if (test?.testing) {
let msg = `Tentanto checar se o contato de numero ${crmPhone} existe no crm`
sendMessageSocket({ companyId, status: 'processing', data: { request: config, msg } })
}
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;
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)
console.log("PAYLOAD CONFIG LOOKUP CONTACT BY PHONE: ", JSON.stringify(config, null, 6))
let data
@ -103,6 +114,7 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
let auxContactId
let auxName
let auxAccountId
let auxContactId2
for (const prop in data) {
@ -116,6 +128,10 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
auxContactId = data[prop]
}
if (_prop == response?.objectId?.trim()) {
auxContactId2 = data[prop]
}
if (auxPhone && auxContactId) break
}
@ -128,6 +144,8 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
let _prop = prop.replace(/\.(\d+)(\.|$)/g, '[$1]$2')
// console.log("_prop: ", _prop, " | response ", JSON.stringify(response, null, 6))
// SALESFORCE GETTING THE NAME
if (_prop == response?.name?.trim()) {
auxName = data[prop]
@ -146,6 +164,10 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
auxContactId = data[prop]
}
if (_prop == response?.objectId?.trim()) {
auxContactId2 = data[prop]
}
// SALESFORCE CASE LOOOK UP ALL THE OBJECT PROPERTIES
if (!url.includes('salesforce'))
if (auxPhone && auxContactId) break
@ -160,7 +182,7 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
auxAccountId = crmAccountId
}
console.log('---------> auxPhone: ', auxPhone, ' | auxContactId: ', auxContactId, ' | auxAccountId: ', auxAccountId)
console.log('---------> auxPhone: ', auxPhone, ' | auxContactId: ', auxContactId, ' | auxAccountId: ', auxAccountId, ' | auxContactId2: ', auxContactId2)
if (auxPhone) {
@ -202,7 +224,7 @@ async function lookupContactByPhone(rest, authentication, crmPhone, companyId, t
}
return { exist: true, contactId: auxContactId, phone: crmPhone, name: auxName, accountId: auxAccountId }
return { exist: true, contactId: auxContactId, phone: crmPhone, name: auxName, accountId: auxAccountId, contactId2: auxContactId2}
}
return { exist: false }

View File

@ -11,7 +11,7 @@ async function templateValidator(crmPhoneTest, crm, companyId) {
let contact = await lookupContactByPhone(
rest = crm.crmRest,
authentication = crm.authentication,
crmPhone = phoneTest,
crmPhone = phoneTest.replace("+", ""),
companyId,
test = { testing: true })

View File

@ -37,6 +37,8 @@ async function whatsappJournalingCRM(companyId, crmPhone = '', crmAgent, crmFirs
let contact = await _lookupContact(rest, authentication, crmPhone, crmEmail, companyId, crmFirstName)
console.log("================> whatsappJournalingCRM contact: ", JSON.stringify(contact, null, 6))
let { request, chats, response } = chatJournaling
let body = findProperty(chats, 'chatDone')
@ -128,7 +130,7 @@ async function _lookupContact(rest, authentication, crmPhone, crmEmail, companyI
// 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 };
return { created: false, contactId: contact.contactId, contactId2: contact?.contactId2 };
}
// 4. Se o contato não foi encontrado por nenhuma das formas, cria um novo
@ -142,7 +144,7 @@ async function _lookupContact(rest, authentication, crmPhone, crmEmail, companyI
// 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 };
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

View File

@ -1,13 +1,13 @@
{
"files": {
"main.css": "/static/css/main.ae60ab08.css",
"main.js": "/static/js/main.b7e32f90.js",
"main.js": "/static/js/main.e3056144.js",
"index.html": "/index.html",
"main.ae60ab08.css.map": "/static/css/main.ae60ab08.css.map",
"main.b7e32f90.js.map": "/static/js/main.b7e32f90.js.map"
"main.e3056144.js.map": "/static/js/main.e3056144.js.map"
},
"entrypoints": [
"static/css/main.ae60ab08.css",
"static/js/main.b7e32f90.js"
"static/js/main.e3056144.js"
]
}

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.b7e32f90.js"></script><link href="/static/css/main.ae60ab08.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.e3056144.js"></script><link href="/static/css/main.ae60ab08.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

File diff suppressed because one or more lines are too long

View File

@ -1,61 +0,0 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/*!
Copyright (c) 2015 Jed Watson.
Based on code that is Copyright 2013-2015, Facebook, Inc.
All rights reserved.
*/
/*!
* Adapted from jQuery UI core
*
* http://jqueryui.com
*
* Copyright 2014 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/category/ui-core/
*/
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/** @license React v0.20.2
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

File diff suppressed because one or more lines are too long