@@ -53,6 +53,10 @@ export class ChatwootService {
5353 private processedOrderIds : Map < string , number > = new Map ( ) ;
5454 private readonly ORDER_CACHE_TTL_MS = 30000 ; // 30 segundos
5555
56+ // Cache para mapeamento LID → Número Normal (resolve problema de @lid)
57+ private lidToPhoneMap : Map < string , { phone : string ; timestamp : number } > = new Map ( ) ;
58+ private readonly LID_CACHE_TTL_MS = 3600000 ; // 1 hora
59+
5660 constructor (
5761 private readonly waMonitor : WAMonitoringService ,
5862 private readonly configService : ConfigService ,
@@ -636,10 +640,32 @@ export class ChatwootService {
636640 public async createConversation ( instance : InstanceDto , body : any ) {
637641 const isLid = body . key . addressingMode === 'lid' ;
638642 const isGroup = body . key . remoteJid . endsWith ( '@g.us' ) ;
639- const phoneNumber = isLid && ! isGroup ? body . key . remoteJidAlt : body . key . remoteJid ;
640- const { remoteJid } = body . key ;
641- const cacheKey = `${ instance . instanceName } :createConversation-${ remoteJid } ` ;
642- const lockKey = `${ instance . instanceName } :lock:createConversation-${ remoteJid } ` ;
643+ let phoneNumber = isLid && ! isGroup ? body . key . remoteJidAlt : body . key . remoteJid ;
644+ let { remoteJid } = body . key ;
645+
646+ // CORREÇÃO LID: Resolve LID para número normal antes de processar
647+ if ( isLid && ! isGroup ) {
648+ const resolvedPhone = await this . resolveLidToPhone ( instance , body . key ) ;
649+
650+ if ( resolvedPhone && resolvedPhone !== remoteJid ) {
651+ this . logger . verbose ( `LID detected and resolved: ${ remoteJid } → ${ resolvedPhone } ` ) ;
652+ phoneNumber = resolvedPhone ;
653+
654+ // Salva mapeamento se temos remoteJidAlt
655+ if ( body . key . remoteJidAlt ) {
656+ this . saveLidMapping ( remoteJid , body . key . remoteJidAlt ) ;
657+ }
658+ } else if ( body . key . remoteJidAlt ) {
659+ // Se não resolveu mas tem remoteJidAlt, usa ele
660+ phoneNumber = body . key . remoteJidAlt ;
661+ this . saveLidMapping ( remoteJid , body . key . remoteJidAlt ) ;
662+ this . logger . verbose ( `Using remoteJidAlt for LID: ${ remoteJid } → ${ phoneNumber } ` ) ;
663+ }
664+ }
665+
666+ // Usa phoneNumber como base para cache (não o LID)
667+ const cacheKey = `${ instance . instanceName } :createConversation-${ phoneNumber } ` ;
668+ const lockKey = `${ instance . instanceName } :lock:createConversation-${ phoneNumber } ` ;
643669 const maxWaitTime = 5000 ; // 5 seconds
644670 const client = await this . clientCw ( instance ) ;
645671 if ( ! client ) return null ;
@@ -2070,6 +2096,29 @@ export class ChatwootService {
20702096 }
20712097 }
20722098
2099+ // CORREÇÃO LID: Resolve LID para número normal antes de processar evento
2100+ if ( body ?. key ?. remoteJid && body . key . remoteJid . includes ( '@lid' ) && ! body . key . remoteJid . endsWith ( '@g.us' ) ) {
2101+ const originalJid = body . key . remoteJid ;
2102+ const resolvedPhone = await this . resolveLidToPhone ( instance , body . key ) ;
2103+
2104+ if ( resolvedPhone && resolvedPhone !== originalJid ) {
2105+ this . logger . verbose ( `Event LID resolved: ${ originalJid } → ${ resolvedPhone } ` ) ;
2106+ body . key . remoteJid = resolvedPhone ;
2107+
2108+ // Salva mapeamento se temos remoteJidAlt
2109+ if ( body . key . remoteJidAlt ) {
2110+ this . saveLidMapping ( originalJid , body . key . remoteJidAlt ) ;
2111+ }
2112+ } else if ( body . key . remoteJidAlt && ! body . key . remoteJidAlt . includes ( '@lid' ) ) {
2113+ // Se não resolveu mas tem remoteJidAlt válido, usa ele
2114+ this . logger . verbose ( `Using remoteJidAlt for event: ${ originalJid } → ${ body . key . remoteJidAlt } ` ) ;
2115+ body . key . remoteJid = body . key . remoteJidAlt ;
2116+ this . saveLidMapping ( originalJid , body . key . remoteJidAlt ) ;
2117+ } else {
2118+ this . logger . warn ( `Could not resolve LID for event, keeping original: ${ originalJid } ` ) ;
2119+ }
2120+ }
2121+
20732122 if ( event === 'messages.upsert' || event === 'send.message' ) {
20742123 this . logger . info ( `[${ event } ] New message received - Instance: ${ JSON . stringify ( body , null , 2 ) } ` ) ;
20752124 if ( body . key . remoteJid === 'status@broadcast' ) {
@@ -2614,6 +2663,82 @@ export class ChatwootService {
26142663 return remoteJid . replace ( / : \d + / , '' ) . split ( '@' ) [ 0 ] ;
26152664 }
26162665
2666+ /**
2667+ * Limpa entradas antigas do cache de mapeamento LID
2668+ */
2669+ private cleanLidCache ( ) {
2670+ const now = Date . now ( ) ;
2671+ this . lidToPhoneMap . forEach ( ( value , lid ) => {
2672+ if ( now - value . timestamp > this . LID_CACHE_TTL_MS ) {
2673+ this . lidToPhoneMap . delete ( lid ) ;
2674+ }
2675+ } ) ;
2676+ }
2677+
2678+ /**
2679+ * Salva mapeamento LID → Número Normal
2680+ */
2681+ private saveLidMapping ( lid : string , phoneNumber : string ) {
2682+ if ( ! lid || ! phoneNumber || ! lid . includes ( '@lid' ) ) {
2683+ return ;
2684+ }
2685+
2686+ this . cleanLidCache ( ) ;
2687+ this . lidToPhoneMap . set ( lid , {
2688+ phone : phoneNumber ,
2689+ timestamp : Date . now ( ) ,
2690+ } ) ;
2691+
2692+ this . logger . verbose ( `LID mapping saved: ${ lid } → ${ phoneNumber } ` ) ;
2693+ }
2694+
2695+ /**
2696+ * Resolve LID para Número Normal
2697+ * Retorna o número normal se encontrado, ou o LID original se não encontrado
2698+ */
2699+ private async resolveLidToPhone ( instance : InstanceDto , messageKey : any ) : Promise < string | null > {
2700+ const { remoteJid, remoteJidAlt } = messageKey ;
2701+
2702+ // Se não for LID, retorna o próprio remoteJid
2703+ if ( ! remoteJid || ! remoteJid . includes ( '@lid' ) ) {
2704+ return remoteJid ;
2705+ }
2706+
2707+ // 1. Tenta buscar no cache
2708+ const cached = this . lidToPhoneMap . get ( remoteJid ) ;
2709+ if ( cached ) {
2710+ this . logger . verbose ( `LID resolved from cache: ${ remoteJid } → ${ cached . phone } ` ) ;
2711+ return cached . phone ;
2712+ }
2713+
2714+ // 2. Se tem remoteJidAlt (número alternativo), usa ele e salva no cache
2715+ if ( remoteJidAlt && ! remoteJidAlt . includes ( '@lid' ) ) {
2716+ this . saveLidMapping ( remoteJid , remoteJidAlt ) ;
2717+ this . logger . verbose ( `LID resolved from remoteJidAlt: ${ remoteJid } → ${ remoteJidAlt } ` ) ;
2718+ return remoteJidAlt ;
2719+ }
2720+
2721+ // 3. Tenta buscar no banco de dados do Chatwoot
2722+ try {
2723+ const lidIdentifier = this . normalizeJidIdentifier ( remoteJid ) ;
2724+ const contact = await this . findContactByIdentifier ( instance , lidIdentifier ) ;
2725+
2726+ if ( contact && contact . phone_number ) {
2727+ // Converte +554498860240 → [email protected] 2728+ const phoneNumber = contact . phone_number . replace ( '+' , '' ) + '@s.whatsapp.net' ;
2729+ this . saveLidMapping ( remoteJid , phoneNumber ) ;
2730+ this . logger . verbose ( `LID resolved from database: ${ remoteJid } → ${ phoneNumber } ` ) ;
2731+ return phoneNumber ;
2732+ }
2733+ } catch ( error ) {
2734+ this . logger . warn ( `Error resolving LID from database: ${ error } ` ) ;
2735+ }
2736+
2737+ // 4. Se não encontrou, retorna null (será necessário criar novo contato)
2738+ this . logger . warn ( `Could not resolve LID: ${ remoteJid } ` ) ;
2739+ return null ;
2740+ }
2741+
26172742 public startImportHistoryMessages ( instance : InstanceDto ) {
26182743 if ( ! this . isImportHistoryAvailable ( ) ) {
26192744 return ;
0 commit comments