Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions src/api/integrations/chatbot/base-chatbot.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,15 @@ export abstract class BaseChatbotService<BotType = any, SettingsType = any> {
try {
if (mediaType === 'audio') {
await instance.audioWhatsapp({
number: remoteJid.split('@')[0],
number: remoteJid,
delay: (settings as any)?.delayMessage || 1000,
audio: url,
caption: altText,
});
} else {
await instance.mediaMessage(
{
number: remoteJid.split('@')[0],
number: remoteJid,
delay: (settings as any)?.delayMessage || 1000,
mediatype: mediaType,
media: url,
Expand Down Expand Up @@ -290,7 +290,7 @@ export abstract class BaseChatbotService<BotType = any, SettingsType = any> {
setTimeout(async () => {
await instance.textMessage(
{
number: remoteJid.split('@')[0],
number: remoteJid,
delay: settings?.delayMessage || 1000,
text: message,
linkPreview,
Expand Down
75 changes: 72 additions & 3 deletions src/api/integrations/chatbot/chatwoot/services/chatwoot.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,16 @@ export class ChatwootService {

return contact;
} catch (error) {
if ((error.status === 422 || error.response?.status === 422) && jid) {
this.logger.warn(`Contact with identifier ${jid} creation failed (422). Checking if it already exists...`);
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;
Expand Down Expand Up @@ -415,6 +425,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);

Expand Down Expand Up @@ -1574,7 +1633,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}`);
}
}
}

Expand Down Expand Up @@ -2024,7 +2087,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();
Expand Down Expand Up @@ -2206,7 +2269,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();
Expand Down Expand Up @@ -2465,6 +2528,12 @@ export class ChatwootService {
}

public getNumberFromRemoteJid(remoteJid: string) {
if (!remoteJid) {
return '';
}
if (remoteJid.includes('@lid')) {
return remoteJid;
}
return remoteJid.replace(/:\d+/, '').split('@')[0];
}

Expand Down
10 changes: 5 additions & 5 deletions src/api/integrations/chatbot/typebot/services/typebot.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
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,
Expand All @@ -342,7 +342,7 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
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,
Expand All @@ -357,7 +357,7 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
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,
Expand Down Expand Up @@ -441,7 +441,7 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
*/
private async processListMessage(instance: any, formattedText: string, remoteJid: string) {
const listJson = {
number: remoteJid.split('@')[0],
number: remoteJid,
title: '',
description: '',
buttonText: '',
Expand Down Expand Up @@ -490,7 +490,7 @@ export class TypebotService extends BaseChatbotService<TypebotModel, any> {
*/
private async processButtonMessage(instance: any, formattedText: string, remoteJid: string) {
const buttonJson = {
number: remoteJid.split('@')[0],
number: remoteJid,
thumbnailUrl: undefined,
title: '',
description: '',
Expand Down
Loading