fix: update remoteJid handling to avoid unnecessary splitting for message number

This commit is contained in:
Vitordotpy 2025-11-28 16:18:33 -03:00
parent 13f96a366b
commit baff4e8f5e
4 changed files with 84 additions and 14 deletions

View File

@ -1614,9 +1614,9 @@ export class BaileysStartupService extends ChannelStartupService {
// This enables LID to phoneNumber conversion without breaking existing webhook consumers // This enables LID to phoneNumber conversion without breaking existing webhook consumers
// Helper to normalize participantId as phone number // 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 // Remove @lid, @s.whatsapp.net suffixes and extract just the number part
return id.split('@')[0]; return String(id || '').split('@')[0];
}; };
try { try {

View File

@ -211,7 +211,7 @@ export abstract class BaseChatbotService<BotType = any, SettingsType = any> {
try { try {
if (mediaType === 'audio') { if (mediaType === 'audio') {
await instance.audioWhatsapp({ await instance.audioWhatsapp({
number: remoteJid.split('@')[0], number: remoteJid,
delay: (settings as any)?.delayMessage || 1000, delay: (settings as any)?.delayMessage || 1000,
audio: url, audio: url,
caption: altText, caption: altText,
@ -219,7 +219,7 @@ export abstract class BaseChatbotService<BotType = any, SettingsType = any> {
} else { } else {
await instance.mediaMessage( await instance.mediaMessage(
{ {
number: remoteJid.split('@')[0], number: remoteJid,
delay: (settings as any)?.delayMessage || 1000, delay: (settings as any)?.delayMessage || 1000,
mediatype: mediaType, mediatype: mediaType,
media: url, media: url,
@ -290,7 +290,7 @@ export abstract class BaseChatbotService<BotType = any, SettingsType = any> {
setTimeout(async () => { setTimeout(async () => {
await instance.textMessage( await instance.textMessage(
{ {
number: remoteJid.split('@')[0], number: remoteJid,
delay: settings?.delayMessage || 1000, delay: settings?.delayMessage || 1000,
text: message, text: message,
linkPreview, linkPreview,

View File

@ -346,6 +346,20 @@ export class ChatwootService {
return contact; return contact;
} catch (error) { } 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'); this.logger.error('Error creating contact');
console.log(error); console.log(error);
return null; 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) { public async findContact(instance: InstanceDto, phoneNumber: string) {
const client = await this.clientCw(instance); const client = await this.clientCw(instance);
@ -1574,7 +1637,11 @@ export class ChatwootService {
this.logger.verbose(`Update result: ${result} rows affected`); this.logger.verbose(`Update result: ${result} rows affected`);
if (this.isImportHistoryAvailable()) { 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')) { if (body.key.remoteJid.includes('@g.us')) {
const participantName = body.pushName; const participantName = body.pushName;
const rawPhoneNumber = 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.participantAlt.split('@')[0].split(':')[0]
: body.key.participant.split('@')[0].split(':')[0]; : body.key.participant.split('@')[0].split(':')[0];
const formattedPhoneNumber = parsePhoneNumberFromString(`+${rawPhoneNumber}`).formatInternational(); const formattedPhoneNumber = parsePhoneNumberFromString(`+${rawPhoneNumber}`).formatInternational();
@ -2206,7 +2273,7 @@ export class ChatwootService {
if (body.key.remoteJid.includes('@g.us')) { if (body.key.remoteJid.includes('@g.us')) {
const participantName = body.pushName; const participantName = body.pushName;
const rawPhoneNumber = 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.participantAlt.split('@')[0].split(':')[0]
: body.key.participant.split('@')[0].split(':')[0]; : body.key.participant.split('@')[0].split(':')[0];
const formattedPhoneNumber = parsePhoneNumberFromString(`+${rawPhoneNumber}`).formatInternational(); const formattedPhoneNumber = parsePhoneNumberFromString(`+${rawPhoneNumber}`).formatInternational();
@ -2465,7 +2532,10 @@ export class ChatwootService {
} }
public getNumberFromRemoteJid(remoteJid: string) { 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) { public startImportHistoryMessages(instance: InstanceDto) {

View File

@ -327,7 +327,7 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
if (message.type === 'image') { if (message.type === 'image') {
await instance.mediaMessage( await instance.mediaMessage(
{ {
number: session.remoteJid.split('@')[0], number: session.remoteJid,
delay: settings?.delayMessage || 1000, delay: settings?.delayMessage || 1000,
mediatype: 'image', mediatype: 'image',
media: message.content.url, media: message.content.url,
@ -342,7 +342,7 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
if (message.type === 'video') { if (message.type === 'video') {
await instance.mediaMessage( await instance.mediaMessage(
{ {
number: session.remoteJid.split('@')[0], number: session.remoteJid,
delay: settings?.delayMessage || 1000, delay: settings?.delayMessage || 1000,
mediatype: 'video', mediatype: 'video',
media: message.content.url, media: message.content.url,
@ -357,7 +357,7 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
if (message.type === 'audio') { if (message.type === 'audio') {
await instance.audioWhatsapp( await instance.audioWhatsapp(
{ {
number: session.remoteJid.split('@')[0], number: session.remoteJid,
delay: settings?.delayMessage || 1000, delay: settings?.delayMessage || 1000,
encoding: true, encoding: true,
audio: message.content.url, audio: message.content.url,
@ -441,7 +441,7 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
*/ */
private async processListMessage(instance: any, formattedText: string, remoteJid: string) { private async processListMessage(instance: any, formattedText: string, remoteJid: string) {
const listJson = { const listJson = {
number: remoteJid.split('@')[0], number: remoteJid,
title: '', title: '',
description: '', description: '',
buttonText: '', buttonText: '',
@ -490,7 +490,7 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
*/ */
private async processButtonMessage(instance: any, formattedText: string, remoteJid: string) { private async processButtonMessage(instance: any, formattedText: string, remoteJid: string) {
const buttonJson = { const buttonJson = {
number: remoteJid.split('@')[0], number: remoteJid,
thumbnailUrl: undefined, thumbnailUrl: undefined,
title: '', title: '',
description: '', description: '',