from odoo.tests.common import TransactionCase from odoo.tools.misc import find_in_path import logging from datetime import datetime _logger = logging.getLogger(__name__) class TestHtmlToPdf(TransactionCase): """ Test the functionality of converting an email to a PDF when it's received for a supplier invoice. This test simulates the full flow of an email being received through the mail alias and verifies that an account move is created with a PDF attachment generated from the email content. It's important to also run the tests in account, which can be done using the test tag: `/account:TestAccountIncomingSupplierInvoice.test_extend_with_attachments_document_formats` This specific test ensures we are not creating more attachments than necessary. """ @classmethod def setUpClass(cls): super().setUpClass() # Set up sender and alias for testing cls.sender_email = "sender@example.com" cls.alias_email = "test-invoices@example.com" # Check if wkhtmltopdf is available cls.wkhtmltopdf_available = bool(find_in_path("wkhtmltopdf")) # Get the model class to access the classmethod cls.account_move = cls.env["account.move"] # Simple test HTML content cls.test_html = """
This is a test paragraph with bold text and italic text.
This is a test invoice from Test Supplier.
Amount: $100.00
Date: 2025-03-27
" # Construct the raw email with proper headers # Make sure the From header is correctly formatted for Odoo to parse raw_email = f"""Return-Path: <{self.sender_email}> X-Original-To: {self.alias_email} Delivered-To: {self.alias_email} Received: from mail.example.com (mail.example.com [192.168.1.1]) From: {self.sender_email} To: {self.alias_email} Subject: {subject} Date: {date} Message-ID: {message_id} MIME-Version: 1.0 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 7bit {html_body}""" # Process the email through the mail gateway # This simulates what happens when fetchmail receives an email invoice_count_before = self.env["account.move"].search_count( [("move_type", "=", "in_invoice")] ) # Process the email through the mail gateway # We need to specify the model explicitly since we're in a test environment # In production, the alias would determine this automatically self.env["mail.thread"].with_context(fetchmail_server_id=1).message_process( model=None, message=raw_email, save_original=True, strip_attachments=False, ) # Count account moves after the test # Note: move_type is the correct field name in Odoo, even if the linter doesn't recognize it move_count_after = self.env["account.move"].search_count( [("move_type", "=", "in_invoice")] ) self.assertEqual( move_count_after, invoice_count_before + 1, "A new account move should be created", ) # Find the newly created invoice invoice = self.env["account.move"].search( [("move_type", "=", "in_invoice")], order="id desc", limit=1 ) self.assertTrue(invoice, "An account move should be created") messages = invoice.message_ids self.assertEqual(len(messages), 1, "The account move should have one message") # Debug message attachments _logger.info("Message ID: %s", messages.id) _logger.info("Message attachments: %s", messages.attachment_ids) _logger.info("Message attachment count: %s", len(messages.attachment_ids)) # Debug all attachments in the system all_attachments = self.env["ir.attachment"].search( [("res_model", "=", "mail.message"), ("res_id", "=", messages.id)] ) _logger.info("All attachments for this message: %s", all_attachments) _logger.info("All attachment count: %s", len(all_attachments)) attachment = messages.attachment_ids self.assertTrue(attachment, "The message should have an attachment") attachment = attachment.filtered( lambda a: a.mimetype == "application/pdf" or ".pdf" in a.name ) self.assertTrue(attachment, "The message should have a PDF attachment") # Verify the invoice is linked to the correct supplier self.assertEqual( invoice.partner_id, self.supplier, "The invoice should be linked to the correct supplier", ) # Verify the invoice type self.assertEqual( invoice.move_type, "in_invoice", "The invoice should be an incoming invoice" )