whatsapp_patch.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import logging
  2. import base64
  3. from odoo.addons.whatsapp.tools.whatsapp_api import WhatsAppApi
  4. _logger = logging.getLogger(__name__)
  5. # Guarda una referencia al método original
  6. original_get_whatsapp_document = WhatsAppApi._get_whatsapp_document
  7. def custom_get_whatsapp_document(self, document_id):
  8. _logger.info("Ejecutando versión modificada de _get_whatsapp_document")
  9. if self.wa_account_id.whatsapp_web_url:
  10. _logger.info(
  11. "Ejecutando versión modificada de _get_whatsapp_document con whatsapp web"
  12. )
  13. try:
  14. result = base64.b64decode(document_id)
  15. except Exception:
  16. # Si falla la decodificación (ej. es un ID y no base64), devolvemos vacío o el ID raw
  17. # para evitar crash, aunque el archivo estará corrupto.
  18. # TODO: Implementar fetch real a WPPConnect
  19. _logger.warning(
  20. "No se pudo decodificar base64 en _get_whatsapp_document, retornando vacío"
  21. )
  22. result = b""
  23. else:
  24. result = original_get_whatsapp_document(self, document_id)
  25. # Aquí puedes modificar 'result' si es necesario antes de devolverlo
  26. return result
  27. # Sobrescribir el método en tiempo de ejecución
  28. WhatsAppApi._get_whatsapp_document = custom_get_whatsapp_document
  29. # Parche para el método _post_whatsapp_reaction para evitar errores de constraint
  30. try:
  31. from odoo.addons.whatsapp.models.mail_message import MailMessage
  32. # Guardar referencia al método original
  33. original_post_whatsapp_reaction = MailMessage._post_whatsapp_reaction
  34. def custom_post_whatsapp_reaction(self, reaction_content, partner_id):
  35. """Parche para evitar error de constraint cuando partner_id es None"""
  36. self.ensure_one()
  37. # Si no hay partner_id, no procesar la reacción
  38. if not partner_id:
  39. _logger.warning(
  40. "Reacción de WhatsApp recibida sin partner_id para mensaje %s - ignorando",
  41. self.id,
  42. )
  43. return
  44. # Llamar al método original si hay partner_id
  45. return original_post_whatsapp_reaction(self, reaction_content, partner_id)
  46. # Aplicar el parche
  47. MailMessage._post_whatsapp_reaction = custom_post_whatsapp_reaction
  48. _logger.info("Parche aplicado exitosamente para _post_whatsapp_reaction")
  49. except ImportError as e:
  50. _logger.warning("No se pudo aplicar el parche para _post_whatsapp_reaction: %s", e)
  51. # Parche para el método wa_phone_format de phone_validation para evitar AttributeError
  52. try:
  53. from odoo.addons.whatsapp.tools import phone_validation
  54. # Guardar referencia al método original
  55. original_wa_phone_format = phone_validation.wa_phone_format
  56. def custom_wa_phone_format(
  57. record,
  58. fname=False,
  59. number=False,
  60. country=None,
  61. force_format="INTERNATIONAL",
  62. raise_exception=True,
  63. ):
  64. """Parche para evitar AttributeError: 'bool' object has no attribute 'italian_leading_zero'"""
  65. # Ejecutar lógica original, pero capturando errores
  66. try:
  67. # Reimplementar la parte final del método original que falla
  68. # Primero llamamos al método original, si funciona, perfecto
  69. return original_wa_phone_format(
  70. record, fname, number, country, force_format, raise_exception
  71. )
  72. except AttributeError as e:
  73. if "italian_leading_zero" in str(e):
  74. _logger.warning(
  75. "Capturado AttributeError en wa_phone_format, intentando recuperación segura: %s",
  76. e,
  77. )
  78. # Intentar replicar la lógica segura aquí si es necesario
  79. # Por ahora, simplemente devolvemos el número formateado si es posible obtenerlo
  80. # o relanzamos si no podemos manejarlo
  81. # Obtener el número base
  82. if not number and record and fname:
  83. record.ensure_one()
  84. number = record[fname]
  85. if not number:
  86. return False
  87. # Si llegamos aquí es porque falló el acceso a atributos de parsed
  88. # Devolvemos el número original o intentamos un formateo básico
  89. return number
  90. raise e
  91. # Una mejor aproximación: Monkey Patch directo a la función interna si es posible,
  92. # o redefinir completamente la función si el error está dentro de ella y no podemos envolverla fácilmente.
  93. # Dado que el error ocurre DENTRO de la función original al acceder a parsed.italian_leading_zero,
  94. # necesitamos redefinir la función completa para corregir el acceso al atributo.
  95. def safe_wa_phone_format(
  96. record,
  97. fname=False,
  98. number=False,
  99. country=None,
  100. force_format="INTERNATIONAL",
  101. raise_exception=True,
  102. ):
  103. """Versión segura de wa_phone_format que maneja correctamente los atributos de parsed"""
  104. # Importar dependencias necesarias
  105. from odoo.addons.phone_validation.tools import phone_validation as pv_tools
  106. if not number and record and fname:
  107. record.ensure_one()
  108. number = record[fname]
  109. if not number:
  110. return False
  111. if not country and record:
  112. country = record._phone_get_country().get(record.id)
  113. if not country:
  114. country = record.env.company.country_id
  115. try:
  116. formatted = pv_tools.phone_format(
  117. number,
  118. country.code,
  119. country.phone_code,
  120. force_format=force_format if force_format != "WHATSAPP" else "E164",
  121. raise_exception=True,
  122. )
  123. except Exception:
  124. if raise_exception:
  125. raise
  126. formatted = False
  127. if formatted and force_format == "WHATSAPP":
  128. try:
  129. parsed = pv_tools.phone_parse(formatted, country.code)
  130. except Exception:
  131. if raise_exception:
  132. raise
  133. return False
  134. zeros = ""
  135. # USO SEGURO DE ATRIBUTOS (Corrección del bug original)
  136. if getattr(parsed, "italian_leading_zero", False):
  137. zeros = "0"
  138. if getattr(parsed, "number_of_leading_zeros", False):
  139. zeros = "0" * parsed.number_of_leading_zeros
  140. # Verificación adicional para country_code y national_number
  141. country_code = getattr(parsed, "country_code", "")
  142. national_number = getattr(parsed, "national_number", "")
  143. if not country_code or not national_number:
  144. # Si no se pueden obtener estos datos, intentar usar el formatted original o un fallback
  145. if formatted:
  146. return formatted
  147. return number
  148. return f"{country_code}" + zeros + f"{national_number}"
  149. return formatted
  150. # Aplicar el parche reemplazando la función en el módulo
  151. phone_validation.wa_phone_format = safe_wa_phone_format
  152. _logger.info("Parche aplicado exitosamente para phone_validation.wa_phone_format")
  153. except ImportError as e:
  154. _logger.warning("No se pudo aplicar el parche para phone_validation: %s", e)
  155. except Exception as e:
  156. _logger.warning("Error al aplicar parche para phone_validation: %s", e)