Skip to content
Open
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
116 changes: 103 additions & 13 deletions src/api/integrations/channel/meta/whatsapp.business.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,88 @@ export class BusinessStartupService extends ChannelStartupService {
if (!data) return;

const content = data.entry[0].changes[0].value;
const normalizedContent = this.normalizeWebhookContent(content);
const remoteId = this.resolveRemoteId(normalizedContent);

try {
this.loadChatwoot();

this.eventHandler(content);
this.eventHandler(normalizedContent);

this.phoneNumber = createJid(content.messages ? content.messages[0].from : content.statuses[0]?.recipient_id);
if (remoteId) {
this.phoneNumber = createJid(remoteId);
}
} catch (error) {
this.logger.error(error);
throw new InternalServerErrorException(error?.toString());
}
}

private normalizeWebhookContent(content: any) {
if (!content || typeof content !== 'object') return content;

const normalized = { ...content };
const messageEchoes = Array.isArray(normalized?.message_echoes) ? normalized.message_echoes : undefined;
const smbMessageEchoes = Array.isArray(normalized?.smb_message_echoes) ? normalized.smb_message_echoes : undefined;
const echoes = messageEchoes?.length ? messageEchoes : smbMessageEchoes?.length ? smbMessageEchoes : undefined;

if (!Array.isArray(normalized.messages) && Array.isArray(echoes) && echoes.length > 0) {
normalized.messages = echoes;
}
Comment thread
sourcery-ai[bot] marked this conversation as resolved.

return normalized;
}

private normalizePhoneNumber(value?: string) {
return typeof value === 'string' ? value.replace(/\D/g, '') : '';
}

private resolveRemoteId(content: any) {
const firstMessage = content?.messages?.[0];
const recipient = content?.statuses?.[0]?.recipient_id;

const candidates = [firstMessage?.from, firstMessage?.to, recipient].filter(Boolean) as string[];
if (candidates.length === 0) return undefined;

const businessNumbers = [
this.normalizePhoneNumber(content?.metadata?.display_phone_number),
this.normalizePhoneNumber(content?.metadata?.phone_number_id),
].filter(Boolean);

const externalCounterpart = candidates.find((candidate) => {
const normalizedCandidate = this.normalizePhoneNumber(candidate);
return normalizedCandidate && !businessNumbers.includes(normalizedCandidate);
});

return externalCounterpart ?? candidates[0];
}

private isCloudApiEchoPayload(received: any) {
return Array.isArray(received?.message_echoes) || Array.isArray(received?.smb_message_echoes);
}

private isCloudApiFromMe(message: any, received: any) {
if (this.isCloudApiEchoPayload(received)) return true;

const from = this.normalizePhoneNumber(message?.from);
const displayPhone = this.normalizePhoneNumber(received?.metadata?.display_phone_number);
const phoneNumberId = this.normalizePhoneNumber(received?.metadata?.phone_number_id);

if (!from) return false;

return from === displayPhone || from === phoneNumberId;
}

private isCloudApiStatusFromMe(item: any, received: any) {
const recipient = this.normalizePhoneNumber(item?.recipient_id);
if (!recipient) return true;

const displayPhone = this.normalizePhoneNumber(received?.metadata?.display_phone_number);
const phoneNumberId = this.normalizePhoneNumber(received?.metadata?.phone_number_id);

return recipient !== displayPhone && recipient !== phoneNumberId;
}

private async downloadMediaMessage(message: any) {
try {
const id = message[message.type].id;
Expand Down Expand Up @@ -386,16 +455,27 @@ export class BusinessStartupService extends ChannelStartupService {
try {
let messageRaw: any;
let pushName: any;
const incomingContact = received?.contacts?.[0];

if (received.contacts) pushName = received.contacts[0].profile.name;
if (incomingContact) {
pushName = incomingContact?.profile?.name ?? incomingContact?.name ?? incomingContact?.wa_id ?? undefined;
}

if (received.messages) {
const message = received.messages[0]; // Añadir esta línea para definir message
const remoteJid = createJid(message?.to ?? message?.from);
const contact = await this.prismaRepository.contact.findFirst({
where: { instanceId: this.instanceId, remoteJid },
});

if (!pushName) {
pushName = contact?.pushName ?? incomingContact?.user_id ?? incomingContact?.wa_id ?? undefined;
}

const key = {
id: message.id,
remoteJid: this.phoneNumber,
fromMe: message.from === received.metadata.phone_number_id,
remoteJid,
fromMe: this.isCloudApiFromMe(message, received),
};

if (message.type === 'sticker') {
Expand Down Expand Up @@ -697,12 +777,11 @@ export class BusinessStartupService extends ChannelStartupService {
});
}

const contact = await this.prismaRepository.contact.findFirst({
where: { instanceId: this.instanceId, remoteJid: key.remoteJid },
});
const contactPhone = incomingContact?.profile?.phone ?? incomingContact?.wa_id ?? message?.to ?? message?.from;
if (!contactPhone) return;

const contactRaw: any = {
remoteJid: received.contacts[0].profile.phone,
remoteJid: createJid(contactPhone),
pushName,
// profilePicUrl: '',
instanceId: this.instanceId,
Expand All @@ -714,7 +793,7 @@ export class BusinessStartupService extends ChannelStartupService {

if (contact) {
const contactRaw: any = {
remoteJid: received.contacts[0].profile.phone,
remoteJid: createJid(contactPhone),
pushName,
// profilePicUrl: '',
instanceId: this.instanceId,
Expand Down Expand Up @@ -745,10 +824,13 @@ export class BusinessStartupService extends ChannelStartupService {
}
if (received.statuses) {
for await (const item of received.statuses) {
const key = {
const remoteId = item?.recipient_id ?? this.phoneNumber;
if (!remoteId) continue;

const key: any = {
id: item.id,
remoteJid: this.phoneNumber,
fromMe: this.phoneNumber === received.metadata.phone_number_id,
remoteJid: createJid(remoteId),
fromMe: this.isCloudApiStatusFromMe(item, received),
};
if (settings?.groups_ignore && key.remoteJid.includes('@g.us')) {
return;
Expand All @@ -768,6 +850,14 @@ export class BusinessStartupService extends ChannelStartupService {
return;
}

const findMessageKey: any = findMessage?.key ?? {};
if (findMessageKey?.remoteJid) {
key.remoteJid = findMessageKey.remoteJid;
}
if (typeof findMessageKey?.fromMe === 'boolean') {
key.fromMe = findMessageKey.fromMe;
}

if (item.message === null && item.status === undefined) {
this.sendDataWebhook(Events.MESSAGES_DELETE, key);

Expand Down