From 7b7f47a361c6c8f90bf9caf8748115c82dd352f7 Mon Sep 17 00:00:00 2001 From: Jeffry Jesus De La Rosa Date: Sun, 27 Apr 2025 00:06:07 -0400 Subject: [PATCH] Update whatsapp.business.service.ts Sticker and Location to Catch it is not available. --- .../channel/meta/whatsapp.business.service.ts | 183 +++++++++++++----- 1 file changed, 132 insertions(+), 51 deletions(-) diff --git a/src/api/integrations/channel/meta/whatsapp.business.service.ts b/src/api/integrations/channel/meta/whatsapp.business.service.ts index de6c50289..406e9f033 100644 --- a/src/api/integrations/channel/meta/whatsapp.business.service.ts +++ b/src/api/integrations/channel/meta/whatsapp.business.service.ts @@ -191,34 +191,64 @@ export class BusinessStartupService extends ChannelStartupService { return content; } - private messageTextJson(received: any) { - let content: any; - const message = received.messages[0]; - if (message.from === received.metadata.phone_number_id) { - content = { - extendedTextMessage: { text: message.text.body }, - }; - message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content; +private messageTextJson(received: any) { + // Verificar que received y received.messages existen + if (!received || !received.messages || received.messages.length === 0) { + this.logger.error('Error: received object or messages array is undefined or empty'); + return null; + } + + const message = received.messages[0]; + let content: any; + + // Verificar si es un mensaje de tipo sticker, location u otro tipo que no tiene text + if (!message.text) { + // Si no hay texto, manejamos diferente según el tipo de mensaje + if (message.type === 'sticker') { + content = { stickerMessage: {} }; + } else if (message.type === 'location') { + content = { locationMessage: { + degreesLatitude: message.location?.latitude, + degreesLongitude: message.location?.longitude, + name: message.location?.name, + address: message.location?.address, + }}; } else { - content = { conversation: message.text.body }; - message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content; + // Para otros tipos de mensajes sin texto, creamos un contenido genérico + this.logger.log(`Mensaje de tipo ${message.type} sin campo text`); + content = { [message.type + 'Message']: message[message.type] || {} }; + } + + // Añadir contexto si existe + if (message.context) { + content = { ...content, contextInfo: { stanzaId: message.context.id } }; } + return content; } + + // Si el mensaje tiene texto, procesamos normalmente + if (!received.metadata || !received.metadata.phone_number_id) { + this.logger.error('Error: metadata or phone_number_id is undefined'); + return null; + } - private messageLocationJson(received: any) { - const message = received.messages[0]; - let content: any = { - locationMessage: { - degreesLatitude: message.location.latitude, - degreesLongitude: message.location.longitude, - name: message.location?.name, - address: message.location?.address, - }, + if (message.from === received.metadata.phone_number_id) { + content = { + extendedTextMessage: { text: message.text.body }, }; - message.context ? (content = { ...content, contextInfo: { stanzaId: message.context.id } }) : content; - return content; + if (message.context) { + content = { ...content, contextInfo: { stanzaId: message.context.id } }; + } + } else { + content = { conversation: message.text.body }; + if (message.context) { + content = { ...content, contextInfo: { stanzaId: message.context.id } }; + } } + + return content; +} private messageContactsJson(received: any) { const message = received.messages[0]; @@ -277,7 +307,7 @@ export class BusinessStartupService extends ChannelStartupService { private renderMessageType(type: string) { let messageType: string; - + switch (type) { case 'text': messageType = 'conversation'; @@ -300,11 +330,14 @@ export class BusinessStartupService extends ChannelStartupService { case 'location': messageType = 'locationMessage'; break; + case 'sticker': + messageType = 'stickerMessage'; + break; default: messageType = 'conversation'; break; } - + return messageType; } @@ -312,16 +345,33 @@ export class BusinessStartupService extends ChannelStartupService { try { let messageRaw: any; let pushName: any; - + if (received.contacts) pushName = received.contacts[0].profile.name; - + if (received.messages) { + const message = received.messages[0]; // Añadir esta línea para definir message + const key = { - id: received.messages[0].id, + id: message.id, remoteJid: this.phoneNumber, - fromMe: received.messages[0].from === received.metadata.phone_number_id, + fromMe: message.from === received.metadata.phone_number_id, }; - if (this.isMediaMessage(received?.messages[0])) { + + if (message.type === 'sticker') { + this.logger.log('Procesando mensaje de tipo sticker'); + messageRaw = { + key, + pushName, + message: { + stickerMessage: message.sticker || {}, + }, + messageType: 'stickerMessage', + messageTimestamp: parseInt(message.timestamp) as number, + source: 'unknown', + instanceId: this.instanceId, + }; + } else if (this.isMediaMessage(message)) { + messageRaw = { key, pushName, @@ -455,17 +505,6 @@ export class BusinessStartupService extends ChannelStartupService { source: 'unknown', instanceId: this.instanceId, }; - } else if (received?.messages[0].location) { - messageRaw = { - key, - pushName, - message: this.messageLocationJson(received), - contextInfo: this.messageLocationJson(received)?.contextInfo, - messageType: this.renderMessageType(received.messages[0].type), - messageTimestamp: parseInt(received.messages[0].timestamp) as number, - source: 'unknown', - instanceId: this.instanceId, - }; } else { messageRaw = { key, @@ -539,7 +578,7 @@ export class BusinessStartupService extends ChannelStartupService { } } - if (!this.isMediaMessage(received?.messages[0])) { + if (!this.isMediaMessage(message) && message.type !== 'sticker') { await this.prismaRepository.message.create({ data: messageRaw, }); @@ -742,10 +781,47 @@ export class BusinessStartupService extends ChannelStartupService { } protected async eventHandler(content: any) { - const database = this.configService.get('DATABASE'); - const settings = await this.findSettings(); - - this.messageHandle(content, database, settings); + try { + // Registro para depuración + this.logger.log('Contenido recibido en eventHandler:'); + this.logger.log(JSON.stringify(content, null, 2)); + + const database = this.configService.get('DATABASE'); + const settings = await this.findSettings(); + + // Si hay mensajes, verificar primero el tipo + if (content.messages && content.messages.length > 0) { + const message = content.messages[0]; + this.logger.log(`Tipo de mensaje recibido: ${message.type}`); + + // Verificamos el tipo de mensaje antes de procesarlo + if (message.type === 'text' || + message.type === 'image' || + message.type === 'video' || + message.type === 'audio' || + message.type === 'document' || + message.type === 'sticker' || + message.type === 'location' || + message.type === 'contacts' || + message.type === 'interactive' || + message.type === 'button' || + message.type === 'reaction') { + + // Procesar el mensaje normalmente + this.messageHandle(content, database, settings); + } else { + this.logger.warn(`Tipo de mensaje no reconocido: ${message.type}`); + } + } else if (content.statuses) { + // Procesar actualizaciones de estado + this.messageHandle(content, database, settings); + } else { + this.logger.warn('No se encontraron mensajes ni estados en el contenido recibido'); + } + } catch (error) { + this.logger.error('Error en eventHandler:'); + this.logger.error(error); + } } protected async sendMessageWithTyping(number: string, message: any, options?: Options, isIntegration = false) { @@ -828,7 +904,6 @@ export class BusinessStartupService extends ChannelStartupService { } if (message['media']) { const isImage = message['mimetype']?.startsWith('image/'); - const isVideo = message['mimetype']?.startsWith('video/'); content = { messaging_product: 'whatsapp', @@ -838,7 +913,7 @@ export class BusinessStartupService extends ChannelStartupService { [message['mediaType']]: { [message['type']]: message['id'], preview_url: linkPreview, - ...(message['fileName'] && !isImage && !isVideo && { filename: message['fileName'] }), + ...(message['fileName'] && !isImage && { filename: message['fileName'] }), caption: message['caption'], }, }; @@ -1006,10 +1081,8 @@ export class BusinessStartupService extends ChannelStartupService { private async getIdMedia(mediaMessage: any) { const formData = new FormData(); - const media = mediaMessage.media || mediaMessage.audio; - if (!media) throw new Error('Media or audio not found'); - const fileStream = createReadStream(media); + const fileStream = createReadStream(mediaMessage.media); formData.append('file', fileStream, { filename: 'media', contentType: mediaMessage.mimetype }); formData.append('typeFile', mediaMessage.mimetype); @@ -1110,7 +1183,7 @@ export class BusinessStartupService extends ChannelStartupService { const prepareMedia: any = { fileName: `${hash}.mp3`, mediaType: 'audio', - audio, + media: audio, }; if (isURL(audio)) { @@ -1132,7 +1205,15 @@ export class BusinessStartupService extends ChannelStartupService { public async audioWhatsapp(data: SendAudioDto, file?: any, isIntegration = false) { const mediaData: SendAudioDto = { ...data }; - if (file) mediaData.audio = file.buffer.toString('base64'); + if (file?.buffer) { + mediaData.audio = file.buffer.toString('base64'); + } else if (isURL(mediaData.audio)) { + // DO NOTHING + // mediaData.audio = mediaData.audio; + } else { + console.error('El archivo no tiene buffer o file es undefined'); + throw new Error('File or buffer is undefined'); + } const message = await this.processAudio(mediaData.audio, data.number);