diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a60b85 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +*.pyc diff --git a/allow_mail_archived_partner/models/__init__.py b/allow_mail_archived_partner/models/__init__.py index a2ad74d..fd6389c 100755 --- a/allow_mail_archived_partner/models/__init__.py +++ b/allow_mail_archived_partner/models/__init__.py @@ -4,4 +4,3 @@ from . import res_partner from . import mail_template from . import mail_compose_message from . import account_move_send -from . import account_move \ No newline at end of file diff --git a/allow_mail_archived_partner/models/account_move_send.py b/allow_mail_archived_partner/models/account_move_send.py index 765d131..1c02848 100755 --- a/allow_mail_archived_partner/models/account_move_send.py +++ b/allow_mail_archived_partner/models/account_move_send.py @@ -1,6 +1,6 @@ def action_send_and_print(self): - _logger.error("🔥 ACCOUNT.INVOICE.SEND action_send_and_print CALLED") - _logger.error("🔥 Wizard partner_ids: %s", self.partner_ids.ids) + # _logger.error("🔥 ACCOUNT.INVOICE.SEND action_send_and_print CALLED") + # _logger.error("🔥 Wizard partner_ids: %s", self.partner_ids.ids) ctx = dict(self.env.context) diff --git a/allow_mail_archived_partner/models/mail_thread.py b/allow_mail_archived_partner/models/mail_thread.py index a2d7713..dd82b0d 100755 --- a/allow_mail_archived_partner/models/mail_thread.py +++ b/allow_mail_archived_partner/models/mail_thread.py @@ -1,4 +1,5 @@ import logging + _logger = logging.getLogger(__name__) from odoo import models @@ -11,95 +12,116 @@ class MailThread(models.AbstractModel): def _notify_thread(self, message, msg_vals=False, **kwargs): """ - Keep the method to avoid TypeError, but keep it simple. + Keep default behavior. """ return super()._notify_thread(message, msg_vals=msg_vals, **kwargs) def _notify_get_recipients(self, message, msg_vals, **kwargs): """ - Force inclusion of archived partners for manual sends ONLY. + Force correct email recipients for manual sends (invoices), + including archived partners, and avoid incomplete recipient dicts. """ - _logger.error("🔥🔥🔥🔥🔥 MailThread._notify_get_recipients CALLED 🔥🔥🔥🔥🔥") - - # CRITICAL: Check if this is a SYSTEM NOTIFICATION + _logger.error("🔥🔥🔥 MailThread._notify_get_recipients CALLED 🔥🔥🔥") + + # --- Ignore system / automatic notifications --- is_system_message = ( - getattr(message, "message_type", None) == "notification" or - getattr(message, "author_id", False) and - message.author_id == self.env.ref("base.partner_root", raise_if_not_found=False) or - (msg_vals and msg_vals.get("message_type") == "notification") + getattr(message, "message_type", None) == "notification" + or ( + getattr(message, "author_id", False) + and message.author_id + == self.env.ref("base.partner_root", raise_if_not_found=False) + ) + or (msg_vals and msg_vals.get("message_type") == "notification") ) - + if is_system_message: - _logger.error("🔥 SYSTEM MESSAGE - returning parent result unchanged") + _logger.debug("SYSTEM MESSAGE – using parent behavior") return super()._notify_get_recipients(message, msg_vals, **kwargs) - - # Check if this is a manual send + + # --- Detect manual send --- is_manual_send = ( - self.env.context.get("mail_notify_force") or - self.env.context.get("include_archived_partners") or - self.env.context.get("force_email") or - self.env.context.get("mark_invoice_as_sent") + self.env.context.get("mail_notify_force") + or self.env.context.get("include_archived_partners") + or self.env.context.get("force_email") + or self.env.context.get("mark_invoice_as_sent") ) - + _logger.error(f"🔥 Is manual send? {is_manual_send}") - _logger.error(f"🔥 Message partner_ids: {getattr(message, 'partner_ids', None)}") - - # For manual sends, we need to handle archived partners - if is_manual_send and hasattr(message, 'partner_ids') and message.partner_ids: - _logger.error("🔥🔥🔥 MANUAL SEND WITH PARTNERS - Handling archived partners 🔥🔥🔥") - - # Get the partner IDs from the message - partner_ids = message.partner_ids.ids - _logger.error(f"🔥 Message has partners: {partner_ids}") - - # Call parent with context that allows archived partners - recipients = super( + _logger.error( + f"🔥 Message partner_ids: {getattr(message, 'partner_ids', None)}" + ) + + if not ( + is_manual_send and hasattr(message, "partner_ids") and message.partner_ids + ): + _logger.debug("Not a manual send or no partners – using parent behavior") + return super()._notify_get_recipients(message, msg_vals, **kwargs) + + # --- Manual send with partners --- + partner_ids = message.partner_ids.ids + _logger.error(f"🔥 Manual send partners: {partner_ids}") + + # Get parent recipients (may be incomplete) + recipients = ( + super( MailThread, self.with_context( active_test=False, include_archived_partners=True, mail_notify_force=True, - ) + ), )._notify_get_recipients(message, msg_vals, **kwargs) - - # Ensure recipients is always a list - if recipients is None: - recipients = [] - - _logger.error(f"🔥 Number of recipients found: {len(recipients)}") - - # If no recipients found, create them manually - if len(recipients) == 0 and partner_ids: - _logger.error("🔥 No recipients found, creating manually") - for partner_id in partner_ids: - partner = self.env['res.partner'].with_context( - active_test=False - ).browse(partner_id) - - if partner.exists() and partner.email: - recipients.append({ - 'id': partner.id, - 'partner_id': partner.id, - 'email': partner.email, - 'name': partner.name, - 'notif': 'email', # Force email notification - 'lang': partner.lang or 'en_US', - 'type': 'customer', - 'is_follower': False, - 'groups': [], - 'notifications': [], - }) - _logger.error(f"🔥 Created recipient for archived partner: {partner.id} - {partner.email}") - - for i, recipient in enumerate(recipients): - _logger.error(f"🔥 Recipient {i}: partner_id={recipient.get('partner_id')}, " - f"notif={recipient.get('notif')}, email={recipient.get('email')}") - - return recipients - - # For non-manual sends, return parent result - _logger.error("🔥 Not a manual send - returning parent result") - return super()._notify_get_recipients(message, msg_vals, **kwargs) + or [] + ) - # Remove _message_post and message_post methods to avoid conflicts - # Keep only the essential methods \ No newline at end of file + _logger.error(f"🔥 Parent returned {len(recipients)} recipients") + + def _is_bad_recipient(r): + return not r or not r.get("email") or not r.get("partner_id") + + bad_recipients = [r for r in recipients if _is_bad_recipient(r)] + + if bad_recipients: + _logger.error( + f"🔥 Found {len(bad_recipients)} incomplete recipient(s), forcing from partner_ids" + ) + + # Build forced recipients from partner_ids + forced_recipients = [] + for partner_id in partner_ids: + partner = ( + self.env["res.partner"] + .with_context(active_test=False) + .browse(partner_id) + ) + + if partner.exists() and partner.email: + forced_recipients.append( + { + "id": partner.id, + "partner_id": partner.id, + "email": partner.email, + "name": partner.name, + "notif": "email", + "lang": partner.lang or "en_US", + "type": "customer", + "is_follower": False, + "groups": [], + "notifications": [], + } + ) + _logger.error(f"🔥 Forced recipient: {partner.id} – {partner.email}") + + # Prefer forced recipients if parent gave nothing useful + if forced_recipients and (not recipients or bad_recipients): + recipients = forced_recipients + + for i, recipient in enumerate(recipients): + _logger.error( + f"🔥 Recipient {i}: " + f"partner_id={recipient.get('partner_id')}, " + f"notif={recipient.get('notif')}, " + f"email={recipient.get('email')}" + ) + + return recipients diff --git a/partner_hierarchical_name/__pycache__/__init__.cpython-312.pyc b/partner_hierarchical_name/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 2851438..0000000 Binary files a/partner_hierarchical_name/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/partner_hierarchical_name/models/__pycache__/__init__.cpython-312.pyc b/partner_hierarchical_name/models/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index 8fab5e6..0000000 Binary files a/partner_hierarchical_name/models/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/partner_hierarchical_name/models/__pycache__/res_partner.cpython-312.pyc b/partner_hierarchical_name/models/__pycache__/res_partner.cpython-312.pyc deleted file mode 100644 index b9fc5fd..0000000 Binary files a/partner_hierarchical_name/models/__pycache__/res_partner.cpython-312.pyc and /dev/null differ