From baff4e8f5efbc57dbb7a5035748702e43f45f72f Mon Sep 17 00:00:00 2001 From: Vitordotpy Date: Fri, 28 Nov 2025 16:18:33 -0300 Subject: [PATCH] fix: update remoteJid handling to avoid unnecessary splitting for message number --- .../whatsapp/whatsapp.baileys.service.ts | 4 +- .../chatbot/base-chatbot.service.ts | 6 +- .../chatwoot/services/chatwoot.service.ts | 78 ++++++++++++++++++- .../typebot/services/typebot.service.ts | 10 +-- 4 files changed, 84 insertions(+), 14 deletions(-) diff --git a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts index c8734201..9b83e609 100644 --- a/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts +++ b/src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts @@ -1614,9 +1614,9 @@ export class BaileysStartupService extends ChannelStartupService { // This enables LID to phoneNumber conversion without breaking existing webhook consumers // Helper to normalize participantId as phone number - const normalizePhoneNumber = (id: string): string => { + const normalizePhoneNumber = (id: string | any): string => { // Remove @lid, @s.whatsapp.net suffixes and extract just the number part - return id.split('@')[0]; + return String(id || '').split('@')[0]; }; try { diff --git a/src/api/integrations/chatbot/base-chatbot.service.ts b/src/api/integrations/chatbot/base-chatbot.service.ts index 11f71b17..064a2a97 100644 --- a/src/api/integrations/chatbot/base-chatbot.service.ts +++ b/src/api/integrations/chatbot/base-chatbot.service.ts @@ -211,7 +211,7 @@ export abstract class BaseChatbotService { try { if (mediaType === 'audio') { await instance.audioWhatsapp({ - number: remoteJid.split('@')[0], + number: remoteJid, delay: (settings as any)?.delayMessage || 1000, audio: url, caption: altText, @@ -219,7 +219,7 @@ export abstract class BaseChatbotService { } else { await instance.mediaMessage( { - number: remoteJid.split('@')[0], + number: remoteJid, delay: (settings as any)?.delayMessage || 1000, mediatype: mediaType, media: url, @@ -290,7 +290,7 @@ export abstract class BaseChatbotService { setTimeout(async () => { await instance.textMessage( { - number: remoteJid.split('@')[0], + number: remoteJid, delay: settings?.delayMessage || 1000, text: message, linkPreview, diff --git a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts index 3b156c31..f6580848 100644 --- a/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts +++ b/src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts @@ -346,6 +346,20 @@ export class ChatwootService { return contact; } catch (error) { + if ( + (error.status === 422 || error.response?.status === 422) && + (error.message?.includes('taken') || error.response?.data?.message?.includes('taken')) && + jid + ) { + this.logger.warn(`Contact with identifier ${jid} already exists, trying to find it...`); + const existingContact = await this.findContactByIdentifier(instance, jid); + if (existingContact) { + const contactId = existingContact.id; + await this.addLabelToContact(this.provider.nameInbox, contactId); + return existingContact; + } + } + this.logger.error('Error creating contact'); console.log(error); return null; @@ -415,6 +429,55 @@ export class ChatwootService { } } + public async findContactByIdentifier(instance: InstanceDto, identifier: string) { + const client = await this.clientCw(instance); + + if (!client) { + this.logger.warn('client not found'); + return null; + } + + // Direct search by query (q) - most common way to search by identifier/email/phone + const contact = (await (client as any).get('contacts/search', { + params: { + q: identifier, + sort: 'name', + }, + })) as any; + + if (contact && contact.data && contact.data.payload && contact.data.payload.length > 0) { + return contact.data.payload[0]; + } + + // Fallback for older API versions or different response structures + if (contact && contact.payload && contact.payload.length > 0) { + return contact.payload[0]; + } + + // Try search by attribute + const contactByAttr = (await (client as any).post('contacts/filter', { + payload: [ + { + attribute_key: 'identifier', + filter_operator: 'equal_to', + values: [identifier], + query_operator: null, + }, + ], + })) as any; + + if (contactByAttr && contactByAttr.payload && contactByAttr.payload.length > 0) { + return contactByAttr.payload[0]; + } + + // Check inside data property if using axios interceptors wrapper + if (contactByAttr && contactByAttr.data && contactByAttr.data.payload && contactByAttr.data.payload.length > 0) { + return contactByAttr.data.payload[0]; + } + + return null; + } + public async findContact(instance: InstanceDto, phoneNumber: string) { const client = await this.clientCw(instance); @@ -1574,7 +1637,11 @@ export class ChatwootService { this.logger.verbose(`Update result: ${result} rows affected`); if (this.isImportHistoryAvailable()) { - chatwootImport.updateMessageSourceID(chatwootMessageIds.messageId, key.id); + try { + await chatwootImport.updateMessageSourceID(chatwootMessageIds.messageId, key.id); + } catch (error) { + this.logger.error(`Error updating Chatwoot message source ID: ${error}`); + } } } @@ -2024,7 +2091,7 @@ export class ChatwootService { if (body.key.remoteJid.includes('@g.us')) { const participantName = body.pushName; const rawPhoneNumber = - body.key.addressingMode === 'lid' && !body.key.fromMe + body.key.addressingMode === 'lid' && !body.key.fromMe && body.key.participantAlt ? body.key.participantAlt.split('@')[0].split(':')[0] : body.key.participant.split('@')[0].split(':')[0]; const formattedPhoneNumber = parsePhoneNumberFromString(`+${rawPhoneNumber}`).formatInternational(); @@ -2206,7 +2273,7 @@ export class ChatwootService { if (body.key.remoteJid.includes('@g.us')) { const participantName = body.pushName; const rawPhoneNumber = - body.key.addressingMode === 'lid' && !body.key.fromMe + body.key.addressingMode === 'lid' && !body.key.fromMe && body.key.participantAlt ? body.key.participantAlt.split('@')[0].split(':')[0] : body.key.participant.split('@')[0].split(':')[0]; const formattedPhoneNumber = parsePhoneNumberFromString(`+${rawPhoneNumber}`).formatInternational(); @@ -2465,7 +2532,10 @@ export class ChatwootService { } public getNumberFromRemoteJid(remoteJid: string) { - return remoteJid.replace(/:\d+/, '').split('@')[0]; + if (!remoteJid) { + return ''; + } + return remoteJid.replace(/:\d+/, '').replace('@s.whatsapp.net', '').replace('@g.us', '').replace('@lid', ''); } public startImportHistoryMessages(instance: InstanceDto) { diff --git a/src/api/integrations/chatbot/typebot/services/typebot.service.ts b/src/api/integrations/chatbot/typebot/services/typebot.service.ts index 68320367..03712bfd 100644 --- a/src/api/integrations/chatbot/typebot/services/typebot.service.ts +++ b/src/api/integrations/chatbot/typebot/services/typebot.service.ts @@ -327,7 +327,7 @@ export class TypebotService extends BaseChatbotService { if (message.type === 'image') { await instance.mediaMessage( { - number: session.remoteJid.split('@')[0], + number: session.remoteJid, delay: settings?.delayMessage || 1000, mediatype: 'image', media: message.content.url, @@ -342,7 +342,7 @@ export class TypebotService extends BaseChatbotService { if (message.type === 'video') { await instance.mediaMessage( { - number: session.remoteJid.split('@')[0], + number: session.remoteJid, delay: settings?.delayMessage || 1000, mediatype: 'video', media: message.content.url, @@ -357,7 +357,7 @@ export class TypebotService extends BaseChatbotService { if (message.type === 'audio') { await instance.audioWhatsapp( { - number: session.remoteJid.split('@')[0], + number: session.remoteJid, delay: settings?.delayMessage || 1000, encoding: true, audio: message.content.url, @@ -441,7 +441,7 @@ export class TypebotService extends BaseChatbotService { */ private async processListMessage(instance: any, formattedText: string, remoteJid: string) { const listJson = { - number: remoteJid.split('@')[0], + number: remoteJid, title: '', description: '', buttonText: '', @@ -490,7 +490,7 @@ export class TypebotService extends BaseChatbotService { */ private async processButtonMessage(instance: any, formattedText: string, remoteJid: string) { const buttonJson = { - number: remoteJid.split('@')[0], + number: remoteJid, thumbnailUrl: undefined, title: '', description: '',