feat: implementation to create ticket by for contacts and individual customers on sap crm to client codWeb 4953 Gradezco colombia
parent
900074adb1
commit
d05bc4c381
|
|
@ -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¶m.Type=COD_CONTACT_TT¶m.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"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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) => {
|
||||
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ const crmTicketSchema = new Schema({
|
|||
type: String,
|
||||
required: true,
|
||||
},
|
||||
ticketId2: {
|
||||
type: String,
|
||||
},
|
||||
contact: {
|
||||
type: mongoose.Schema.ObjectId,
|
||||
ref: 'contact',
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
@ -95,8 +109,6 @@ async function createContact(companyId, rest, authentication, crmPhone = '', crm
|
|||
throw error
|
||||
}
|
||||
|
||||
// let { data } = await axios(config)
|
||||
|
||||
data = flatten(data)
|
||||
|
||||
let auxContactId
|
||||
|
|
@ -124,7 +136,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, contactId2: auxContactId2}
|
||||
return { exist: true, contactId: auxContactId, phone: crmPhone, contactId2: auxContactId2, flow: flow }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
@ -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') {
|
||||
|
||||
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 []
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
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,6 +202,8 @@ 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) {
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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,12 +29,27 @@ 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
|
||||
|
|
@ -41,25 +57,35 @@ async function ticketCRM(companyId, crmPhone, crmAgent = "0000", crmFirstName =
|
|||
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 }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue