@@ -127,20 +127,99 @@ export class BusinessStartupService extends ChannelStartupService {
127127 if ( ! data ) return ;
128128
129129 const content = data . entry [ 0 ] . changes [ 0 ] . value ;
130+ const normalizedContent = this . normalizeWebhookContent ( content ) ;
131+ const remoteId = this . resolveRemoteId ( normalizedContent ) ;
130132
131133 try {
132134 this . loadChatwoot ( ) ;
133135
134- const senderJid = createJid ( content . messages ? content . messages [ 0 ] . from : content . statuses [ 0 ] ?. recipient_id ) ;
135- this . phoneNumber = senderJid ;
136+ await this . eventHandler ( normalizedContent ) ;
136137
137- await this . eventHandler ( content , senderJid ) ;
138+ if ( remoteId ) {
139+ this . phoneNumber = createJid ( remoteId ) ;
140+ }
138141 } catch ( error ) {
139142 this . logger . error ( error ) ;
140143 throw new InternalServerErrorException ( error ?. toString ( ) ) ;
141144 }
142145 }
143146
147+ private normalizeWebhookContent ( content : any ) {
148+ if ( ! content || typeof content !== 'object' ) return content ;
149+
150+ const normalized = { ...content } ;
151+ const messageEchoes = Array . isArray ( normalized ?. message_echoes ) ? normalized . message_echoes : undefined ;
152+ const smbMessageEchoes = Array . isArray ( normalized ?. smb_message_echoes ) ? normalized . smb_message_echoes : undefined ;
153+ const echoes = messageEchoes ?. length ? messageEchoes : smbMessageEchoes ?. length ? smbMessageEchoes : undefined ;
154+
155+ if ( ! Array . isArray ( normalized . messages ) && Array . isArray ( echoes ) && echoes . length > 0 ) {
156+ normalized . messages = echoes ;
157+ }
158+
159+ return normalized ;
160+ }
161+
162+ private normalizePhoneNumber ( value ?: string ) {
163+ return typeof value === 'string' ? value . replace ( / \D / g, '' ) : '' ;
164+ }
165+
166+ private resolveRemoteId ( content : any ) {
167+ const firstMessage = content ?. messages ?. [ 0 ] ;
168+ const recipient = content ?. statuses ?. [ 0 ] ?. recipient_id ;
169+
170+ const candidates = [ firstMessage ?. from , firstMessage ?. to , recipient ] . filter ( Boolean ) as string [ ] ;
171+ if ( candidates . length === 0 ) return undefined ;
172+
173+ const businessNumbers = [
174+ this . normalizePhoneNumber ( content ?. metadata ?. display_phone_number ) ,
175+ this . normalizePhoneNumber ( content ?. metadata ?. phone_number_id ) ,
176+ ] . filter ( Boolean ) ;
177+
178+ const externalCounterpart = candidates . find ( ( candidate ) => {
179+ const normalizedCandidate = this . normalizePhoneNumber ( candidate ) ;
180+ return normalizedCandidate && ! businessNumbers . includes ( normalizedCandidate ) ;
181+ } ) ;
182+
183+ return externalCounterpart ?? candidates [ 0 ] ;
184+ }
185+
186+ private isCloudApiEchoPayload ( received : any ) {
187+ return (
188+ ( Array . isArray ( received ?. message_echoes ) && received . message_echoes . length > 0 ) ||
189+ ( Array . isArray ( received ?. smb_message_echoes ) && received . smb_message_echoes . length > 0 )
190+ ) ;
191+ }
192+
193+ private resolveMessageRemoteId ( message : any , received : any ) {
194+ if ( this . isCloudApiEchoPayload ( received ) ) {
195+ return message ?. to ?? message ?. from ;
196+ }
197+
198+ return message ?. from ?? message ?. to ;
199+ }
200+
201+ private isCloudApiFromMe ( message : any , received : any ) {
202+ if ( this . isCloudApiEchoPayload ( received ) ) return true ;
203+
204+ const from = this . normalizePhoneNumber ( message ?. from ) ;
205+ const displayPhone = this . normalizePhoneNumber ( received ?. metadata ?. display_phone_number ) ;
206+ const phoneNumberId = this . normalizePhoneNumber ( received ?. metadata ?. phone_number_id ) ;
207+
208+ if ( ! from ) return false ;
209+
210+ return from === displayPhone || from === phoneNumberId ;
211+ }
212+
213+ private isCloudApiStatusFromMe ( item : any , received : any ) {
214+ const recipient = this . normalizePhoneNumber ( item ?. recipient_id ) ;
215+ if ( ! recipient ) return true ;
216+
217+ const displayPhone = this . normalizePhoneNumber ( received ?. metadata ?. display_phone_number ) ;
218+ const phoneNumberId = this . normalizePhoneNumber ( received ?. metadata ?. phone_number_id ) ;
219+
220+ return recipient !== displayPhone && recipient !== phoneNumberId ;
221+ }
222+
144223 private async downloadMediaMessage ( message : any ) {
145224 try {
146225 const id = message [ message . type ] . id ;
@@ -383,20 +462,34 @@ export class BusinessStartupService extends ChannelStartupService {
383462 return messageType ;
384463 }
385464
386- protected async messageHandle ( received : any , database : Database , settings : any , senderJid : string ) {
465+ protected async messageHandle ( received : any , database : Database , settings : any ) {
387466 try {
388467 let messageRaw : any ;
389468 let pushName : any ;
469+ const incomingContact = received ?. contacts ?. [ 0 ] ;
390470
391- if ( received . contacts ) pushName = received . contacts [ 0 ] . profile . name ;
471+ if ( incomingContact ) {
472+ pushName = incomingContact ?. profile ?. name ?? incomingContact ?. name ?? incomingContact ?. wa_id ?? undefined ;
473+ }
392474
393475 if ( received . messages ) {
394476 const message = received . messages [ 0 ] ;
477+ const remoteId = this . resolveMessageRemoteId ( message , received ) ;
478+ if ( ! remoteId ) return ;
479+
480+ const remoteJid = createJid ( remoteId ) ;
481+ const contact = await this . prismaRepository . contact . findFirst ( {
482+ where : { instanceId : this . instanceId , remoteJid } ,
483+ } ) ;
484+
485+ if ( ! pushName ) {
486+ pushName = contact ?. pushName ?? incomingContact ?. user_id ?? incomingContact ?. wa_id ?? undefined ;
487+ }
395488
396489 const key = {
397490 id : message . id ,
398- remoteJid : senderJid ,
399- fromMe : message . from === received . metadata . phone_number_id ,
491+ remoteJid,
492+ fromMe : this . isCloudApiFromMe ( message , received ) ,
400493 } ;
401494
402495 if ( message . type === 'sticker' ) {
@@ -699,12 +792,11 @@ export class BusinessStartupService extends ChannelStartupService {
699792 } ) ;
700793 }
701794
702- const contact = await this . prismaRepository . contact . findFirst ( {
703- where : { instanceId : this . instanceId , remoteJid : key . remoteJid } ,
704- } ) ;
795+ const contactPhone = incomingContact ?. profile ?. phone ?? incomingContact ?. wa_id ?? remoteId ;
796+ if ( ! contactPhone ) return ;
705797
706798 const contactRaw : any = {
707- remoteJid : received . contacts [ 0 ] . profile . phone ,
799+ remoteJid : createJid ( contactPhone ) ,
708800 pushName,
709801 // profilePicUrl: '',
710802 instanceId : this . instanceId ,
@@ -716,7 +808,7 @@ export class BusinessStartupService extends ChannelStartupService {
716808
717809 if ( contact ) {
718810 const contactRaw : any = {
719- remoteJid : received . contacts [ 0 ] . profile . phone ,
811+ remoteJid : createJid ( contactPhone ) ,
720812 pushName,
721813 // profilePicUrl: '',
722814 instanceId : this . instanceId ,
@@ -747,10 +839,13 @@ export class BusinessStartupService extends ChannelStartupService {
747839 }
748840 if ( received . statuses ) {
749841 for await ( const item of received . statuses ) {
750- const key = {
842+ const remoteId = item ?. recipient_id ?? this . phoneNumber ;
843+ if ( ! remoteId ) continue ;
844+
845+ const key : any = {
751846 id : item . id ,
752- remoteJid : senderJid ,
753- fromMe : senderJid === received . metadata . phone_number_id ,
847+ remoteJid : createJid ( remoteId ) ,
848+ fromMe : this . isCloudApiStatusFromMe ( item , received ) ,
754849 } ;
755850 if ( settings ?. groups_ignore && key . remoteJid . includes ( '@g.us' ) ) {
756851 return ;
@@ -770,6 +865,14 @@ export class BusinessStartupService extends ChannelStartupService {
770865 return ;
771866 }
772867
868+ const findMessageKey : any = findMessage ?. key ?? { } ;
869+ if ( findMessageKey ?. remoteJid ) {
870+ key . remoteJid = findMessageKey . remoteJid ;
871+ }
872+ if ( typeof findMessageKey ?. fromMe === 'boolean' ) {
873+ key . fromMe = findMessageKey . fromMe ;
874+ }
875+
773876 if ( item . message === null && item . status === undefined ) {
774877 this . sendDataWebhook ( Events . MESSAGES_DELETE , key ) ;
775878
@@ -895,7 +998,7 @@ export class BusinessStartupService extends ChannelStartupService {
895998 return message ;
896999 }
8971000
898- protected async eventHandler ( content : any , senderJid : string ) {
1001+ protected async eventHandler ( content : any ) {
8991002 try {
9001003 this . logger . log ( 'Contenido recibido en eventHandler:' ) ;
9011004 this . logger . log ( JSON . stringify ( content , null , 2 ) ) ;
@@ -920,12 +1023,12 @@ export class BusinessStartupService extends ChannelStartupService {
9201023 message . type === 'button' ||
9211024 message . type === 'reaction'
9221025 ) {
923- await this . messageHandle ( content , database , settings , senderJid ) ;
1026+ await this . messageHandle ( content , database , settings ) ;
9241027 } else {
9251028 this . logger . warn ( `Tipo de mensaje no reconocido: ${ message . type } ` ) ;
9261029 }
9271030 } else if ( content . statuses ) {
928- await this . messageHandle ( content , database , settings , senderJid ) ;
1031+ await this . messageHandle ( content , database , settings ) ;
9291032 } else {
9301033 this . logger . warn ( 'No se encontraron mensajes ni estados en el contenido recibido' ) ;
9311034 }
0 commit comments