whatsapp_patch.py 6.8 KB

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