further fixes and tests for email_to_pdf

This commit is contained in:
Marc Durepos 2025-03-27 11:23:58 -04:00
parent f3259fd6a1
commit ad2bc057a2
4 changed files with 119 additions and 10 deletions

View file

@ -28,8 +28,19 @@ class AccountMove(models.Model):
# Create a PDF from the email content
pdf_attachment = self._create_pdf_from_email(message_dict)
if pdf_attachment:
# Add the PDF to the attachments list
return super()._check_and_decode_attachment([pdf_attachment])
_logger.info(
"Successfully created PDF attachment, proceeding with invoice creation"
)
# We need to return the result of _extend_with_attachments directly
# as that's what the original method would return
# Convert the list to a recordset before passing to _extend_with_attachments
attachment_recordset = self.env["ir.attachment"].browse(
[pdf_attachment.id]
)
return self._extend_with_attachments(
attachment_recordset,
new=bool(self._context.get("from_alias")),
)
except Exception as e:
_logger.exception("Error creating PDF from email: %s", e)
@ -110,7 +121,14 @@ class AccountMove(models.Model):
_logger.error("Failed to remove temporary files")
def _create_pdf_from_email(self, message_dict):
"""Create a PDF attachment from an email message."""
"""Create a PDF attachment from an email message.
Args:
message_dict (dict): Email message dictionary
Returns:
ir.attachment: The created attachment record or False if failed
"""
# Extract email details
email_from = message_dict.get("email_from", "Unknown Sender")
email_date = message_dict.get("date", datetime.now())
@ -151,13 +169,16 @@ class AccountMove(models.Model):
if not pdf_content:
return False
# Create attachment tuple (filename, content, mime_type)
# Create a proper ir.attachment record
filename = f"Email_{subject.replace(' ', '_')[:30]}.pdf"
attachment = (
filename,
base64.b64encode(pdf_content).decode("utf-8"),
"application/pdf",
)
attachment_vals = {
"name": filename,
"datas": base64.b64encode(pdf_content),
"mimetype": "application/pdf",
"res_model": "mail.message",
"res_id": message_dict.get("id", 0),
}
attachment = self.env["ir.attachment"].create(attachment_vals)
_logger.info("Created PDF attachment from email: %s", filename)
return attachment

View file

@ -1 +1,2 @@
from . import test_email_to_pdf
from . import test_email_integration

View file

@ -0,0 +1,88 @@
import base64
from odoo.tests.common import TransactionCase
from odoo.tools.misc import find_in_path
from unittest.mock import patch
class TestEmailProcessing(TransactionCase):
"""Integration tests for email processing with PDF generation."""
@classmethod
def setUpClass(cls):
super().setUpClass()
# Check if wkhtmltopdf is available
cls.wkhtmltopdf_available = bool(find_in_path("wkhtmltopdf"))
# Get the model class to access the methods
cls.account_move = cls.env["account.move"]
def test_create_pdf_from_email(self):
"""Test that an email without attachments can be converted to PDF.
This test directly verifies that the _create_pdf_from_email method
correctly generates a PDF attachment from an email message without
attachments, allowing the invoice creation process to continue.
"""
if not self.wkhtmltopdf_available:
self.skipTest("wkhtmltopdf not available")
# Create a sample email message dictionary (similar to what would be parsed from an email)
message_dict = {
"subject": "Test Invoice",
"from": "test@example.com",
"to": "invoices@example.com",
"body": "<html><body><h1>Invoice Test</h1><p>This is a test invoice.</p></body></html>",
"attachments": [], # No attachments
"message_id": "<test123@example.com>",
}
# Call the method directly to create a PDF from the email
attachment = self.account_move._create_pdf_from_email(message_dict)
# Verify that an attachment was created
self.assertTrue(attachment, "An attachment should have been created")
# The actual name format is 'Email_' + subject + '.pdf' with spaces replaced by underscores
self.assertEqual(
attachment.name,
"Email_Test_Invoice.pdf",
"Attachment name should match expected format",
)
self.assertEqual(
attachment.mimetype, "application/pdf", "Attachment should be a PDF"
)
# Verify the content of the PDF attachment
pdf_data = base64.b64decode(attachment.datas)
self.assertTrue(pdf_data.startswith(b"%PDF-"), "Content should be a valid PDF")
self.assertTrue(len(pdf_data) > 100, "PDF should have a reasonable size")
def test_check_and_decode_attachment_with_empty_attachments(self):
"""Test that _check_and_decode_attachment doesn't reject emails with no attachments."""
if not self.wkhtmltopdf_available:
self.skipTest("wkhtmltopdf not available")
# Set up a context with a message_dict to simulate email processing
message_dict = {
"subject": "Test Invoice",
"from": "test@example.com",
"to": "invoices@example.com",
"body": "<html><body><h1>Invoice Test</h1><p>This is a test invoice.</p></body></html>",
"attachments": [], # No attachments
"message_id": "<test123@example.com>",
}
# Call the method with an empty attachments list
# We need to pass the message_dict in the context so _create_pdf_from_email can access it
result = self.account_move.with_context(
message_dict=message_dict
)._check_and_decode_attachment([])
# Verify that the result is not False (which would mean email rejection)
self.assertNotEqual(
result,
False,
"Should not reject the email when no attachments are provided",
)
# Verify that the result contains attachment data
self.assertTrue(result, "Should return attachment data")

View file

@ -1,4 +1,3 @@
import base64
from odoo.tests.common import TransactionCase
from odoo.tools.misc import find_in_path