Vendor Bill Created
', 'Only the invoice creation should be posted') self.assertRegex(invoice.name_placeholder, r'BILL/\d{4}/\d{2}/0001') def test_supplier_invoice_forwarded_by_internal_user_without_supplier(self): """ In this test, the bill was forwarded by an employee, but no partner email address is found in the body.""" message_parsed = { 'message_id': 'message-id-dead-beef', 'message_type': 'email', 'subject': 'Incoming bill', 'from': '%s <%s>' % (self.internal_user.name, self.internal_user.email), 'to': '%s@%s' % (self.journal.alias_id.alias_name, self.journal.alias_id.alias_domain), 'body': "You know, that thing that you bought.", 'attachments': [b'Hello, invoice'], } invoice = self.env['account.move'].message_new(message_parsed, {'move_type': 'in_invoice', 'journal_id': self.journal.id}) self.assertFalse(invoice.partner_id) message_ids = invoice.message_ids self.assertEqual(len(message_ids), 1, 'Only one message should be posted in the chatter') self.assertEqual(message_ids.body, 'Vendor Bill Created
', 'Only the invoice creation should be posted') self.assertEqual(invoice.message_partner_ids, self.env.user.partner_id) def test_supplier_invoice_forwarded_by_internal_with_supplier_in_body(self): """ In this test, the bill was forwarded by an employee, and the partner email address is found in the body.""" message_parsed = { 'message_id': 'message-id-dead-beef', 'message_type': 'email', 'subject': 'Incoming bill', 'from': '%s <%s>' % (self.internal_user.name, self.internal_user.email), 'to': '%s@%s' % (self.journal.alias_id.alias_name, self.journal.alias_id.alias_domain), 'body': "Mail sent by %s <%s>:\nYou know, that thing that you bought." % (self.supplier_partner.name, self.supplier_partner.email), 'attachments': [b'Hello, invoice'], } invoice = self.env['account.move'].message_new(message_parsed, {'move_type': 'in_invoice', 'journal_id': self.journal.id}) self.assertEqual(invoice.partner_id, self.supplier_partner) message_ids = invoice.message_ids self.assertEqual(len(message_ids), 1, 'Only one message should be posted in the chatter') self.assertEqual(message_ids.body, 'Vendor Bill Created
', 'Only the invoice creation should be posted') following_partners = invoice.message_follower_ids.mapped('partner_id') self.assertEqual(following_partners, self.env.user.partner_id) def test_supplier_invoice_forwarded_by_internal_with_internal_in_body(self): """ In this test, the bill was forwarded by an employee, and the internal user email address is found in the body.""" message_parsed = { 'message_id': 'message-id-dead-beef', 'message_type': 'email', 'subject': 'Incoming bill', 'from': '%s <%s>' % (self.internal_user.name, self.internal_user.email), 'to': '%s@%s' % (self.journal.alias_id.alias_name, self.journal.alias_id.alias_domain), 'body': "Mail sent by %s <%s>:\nYou know, that thing that you bought." % (self.internal_user.name, self.internal_user.email), 'attachments': [b'Hello, invoice'], } invoice = self.env['account.move'].message_new(message_parsed, {'move_type': 'in_invoice', 'journal_id': self.journal.id}) self.assertFalse(invoice.partner_id) message_ids = invoice.message_ids self.assertEqual(len(message_ids), 1, 'Only one message should be posted in the chatter') self.assertEqual(message_ids.body, 'Vendor Bill Created
', 'Only the invoice creation should be posted') following_partners = invoice.message_follower_ids.mapped('partner_id') self.assertEqual(following_partners, self.env.user.partner_id) def test_supplier_invoice_forwarded_by_internal_with_unknown_supplier_in_body(self): """ In this test, the bill was forwarded by an employee, and an unknown partner email address is found in the body.""" message_parsed = { 'message_id': 'message-id-dead-beef', 'message_type': 'email', 'subject': 'Incoming bill', 'from': '%s <%s>' % (self.internal_user.name, self.internal_user.email), 'to': '%s@%s' % (self.journal.alias_id.alias_name, self.journal.alias_id.alias_domain), 'body': "Mail sent by %s <%s>:\nYou know, that thing that you bought." % ("Test supplier", "unknown_supplier@other.com"), 'attachments': [b'Hello, invoice'], } invoice = self.env['account.move'].message_new(message_parsed, {'move_type': 'in_invoice', 'journal_id': self.journal.id}) self.assertFalse(invoice.partner_id) message_ids = invoice.message_ids self.assertEqual(len(message_ids), 1, 'Only one message should be posted in the chatter') self.assertEqual(message_ids.body, 'Vendor Bill Created
', 'Only the invoice creation should be posted') following_partners = invoice.message_follower_ids.mapped('partner_id') self.assertEqual(following_partners, self.env.user.partner_id) def test_einvoice_notification(self): purchase_journal = self.company_data['default_journal_purchase'] purchase_journal.incoming_einvoice_notification_email = 'oops_another_bill@example.com' with self.mock_mail_gateway(): self.assert_attachment_import( origin='mail_alias', attachments_vals=[self.pdf1_vals], expected_invoices={ 1: { 'invoice1.pdf': {'on_message': True, 'on_invoice': True, 'is_decoded': True, 'is_new': True}, 'MAIL_invoice1.pdf': {'on_message': True}, }, }, ) self.assertSentEmail( self.company_data['company'].email_formatted, ['oops_another_bill@example.com'], subject=f"{self.company_data['company'].name} - New invoice in {purchase_journal.display_name} journal", ) def test_01_decoder_called(self): move = self.env['account.move'].create({'move_type': 'in_invoice'}) attachment = self.env['ir.attachment'].create(self.xml1_vals) with self._patch_import_methods(): move.message_post(message_type='comment', attachment_ids=attachment.ids) self.assertEqual(move.partner_id, self.partner_a) def test_02_decoder_not_called_if_invoice_has_lines(self): move = self.env['account.move'].create({ 'move_type': 'in_invoice', 'invoice_line_ids': [ Command.create({ 'balance': 100, }) ] }) attachment = self.env['ir.attachment'].create(self.xml1_vals) with self._patch_import_methods(): move.message_post(message_type='comment', attachment_ids=attachment.ids) self.assertFalse(move.partner_id) def test_10_chatter_upload_pdfs(self): self.assert_attachment_import( origin='chatter_upload', attachments_vals=[self.pdf1_vals, self.pdf2_vals], expected_invoices={ 1: { 'invoice1.pdf': {'on_invoice': True, 'is_decoded': True}, 'invoice2.pdf': {'on_invoice': True}, } }, ) def test_11_chatter_message_pdfs(self): self.assert_attachment_import( origin='chatter_message', attachments_vals=[self.pdf1_vals, self.pdf2_vals], expected_invoices={ 1: { 'invoice1.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True}, 'invoice2.pdf': {'on_invoice': True, 'on_message': True}, } }, ) def test_12_chatter_email_pdfs(self): self.assert_attachment_import( origin='chatter_email', attachments_vals=[self.pdf1_vals, self.pdf2_vals], expected_invoices={ 1: { 'invoice1.pdf': {'on_invoice': True, 'on_message': True}, 'invoice2.pdf': {'on_invoice': True, 'on_message': True}, } }, ) def test_13_journal_upload_pdfs(self): self.assert_attachment_import( origin='journal', attachments_vals=[self.pdf1_vals, self.pdf2_vals], expected_invoices={ 1: {'invoice1.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, 2: {'invoice2.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, }, ) def test_14_mail_alias_pdfs(self): self.assert_attachment_import( origin='mail_alias', attachments_vals=[self.pdf1_vals, self.pdf2_vals], expected_invoices={ 1: {'invoice1.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, 2: {'invoice2.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, }, ) def test_20_chatter_upload_pdfs_and_gifs(self): self.assert_attachment_import( origin='chatter_upload', attachments_vals=[self.pdf1_vals, self.pdf2_vals, self.gif1_vals, self.gif2_vals], expected_invoices={ 1: { 'invoice1.pdf': {'on_invoice': True, 'is_decoded': True}, 'invoice2.pdf': {'on_invoice': True}, 'gif1.gif': {'on_invoice': True}, 'gif2.gif': {'on_invoice': True}, }, }, ) def test_21_chatter_message_pdfs_and_gifs(self): self.assert_attachment_import( origin='chatter_message', attachments_vals=[self.pdf1_vals, self.pdf2_vals, self.gif1_vals, self.gif2_vals], expected_invoices={ 1: { 'invoice1.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True}, 'invoice2.pdf': {'on_invoice': True, 'on_message': True}, 'gif1.gif': {'on_message': True}, 'gif2.gif': {'on_message': True}, }, }, ) def test_22_chatter_email_pdfs_and_gifs(self): self.assert_attachment_import( origin='chatter_email', attachments_vals=[self.pdf1_vals, self.pdf2_vals, self.gif1_vals, self.gif2_vals], expected_invoices={ 1: { 'invoice1.pdf': {'on_invoice': True, 'on_message': True}, 'invoice2.pdf': {'on_invoice': True, 'on_message': True}, 'gif1.gif': {'on_message': True}, 'gif2.gif': {'on_message': True}, }, }, ) def test_23_journal_upload_pdfs_and_gifs(self): self.assert_attachment_import( origin='journal', attachments_vals=[self.pdf1_vals, self.pdf2_vals, self.gif1_vals, self.gif2_vals], expected_invoices={ 1: {'invoice1.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, 2: {'invoice2.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, 3: {'gif1.gif': {'on_invoice': True, 'on_message': True}}, 4: {'gif2.gif': {'on_invoice': True, 'on_message': True}}, }, ) def test_24_mail_alias_pdfs_and_gifs(self): self.assert_attachment_import( origin='mail_alias', attachments_vals=[self.pdf1_vals, self.pdf2_vals, self.gif1_vals, self.gif2_vals], expected_invoices={ 1: { 'invoice1.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}, 'gif1.gif': {'on_message': True}, 'gif2.gif': {'on_message': True}, }, 2: {'invoice2.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, }, ) def test_25_mail_alias_gifs(self): self.assert_attachment_import( origin='mail_alias', attachments_vals=[self.gif1_vals, self.gif2_vals], expected_invoices={ 1: { 'gif1.gif': {'on_message': True}, 'gif2.gif': {'on_message': True}, }, }, ) def test_30_chatter_upload_pdf_and_xml(self): self.assert_attachment_import( origin='chatter_upload', attachments_vals=[self.pdf1_vals, self.xml1_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_invoice': True, 'is_decoded': True}, 'invoice1.pdf': {'on_invoice': True}, }, }, ) def test_31_chatter_message_pdf_and_xml(self): self.assert_attachment_import( origin='chatter_message', attachments_vals=[self.pdf1_vals, self.xml1_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_message': True, 'is_decoded': True}, 'invoice1.pdf': {'on_invoice': True, 'on_message': True}, }, }, ) def test_32_chatter_email_pdf_and_xml(self): self.assert_attachment_import( origin='chatter_email', attachments_vals=[self.pdf1_vals, self.xml1_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_message': True}, 'invoice1.pdf': {'on_invoice': True, 'on_message': True}, }, }, ) def test_33_journal_upload_pdf_and_xml(self): self.assert_attachment_import( origin='journal', attachments_vals=[self.pdf1_vals, self.xml1_vals], expected_invoices={ 1: {'invoice1.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, 2: {'invoice1.xml': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, }, ) def test_34_mail_alias_pdf_and_xml(self): self.assert_attachment_import( origin='mail_alias', attachments_vals=[self.pdf1_vals, self.xml1_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_message': True, 'is_decoded': True, 'is_new': True}, 'invoice1.pdf': {'on_invoice': True, 'on_message': True}, }, }, ) def test_40_chatter_upload_xmls(self): self.assert_attachment_import( origin='chatter_upload', attachments_vals=[self.xml1_vals, self.xml2_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_invoice': True, 'is_decoded': True}, 'invoice2.xml': {'on_invoice': True}, }, }, ) def test_41_chatter_message_xmls(self): self.assert_attachment_import( origin='chatter_message', attachments_vals=[self.xml1_vals, self.xml2_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_message': True, 'is_decoded': True}, 'invoice2.xml': {'on_message': True}, }, }, ) def test_42_chatter_email_xmls(self): self.assert_attachment_import( origin='chatter_email', attachments_vals=[self.xml1_vals, self.xml2_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_message': True}, 'invoice2.xml': {'on_message': True}, }, }, ) def test_43_journal_upload_xmls(self): self.assert_attachment_import( origin='journal', attachments_vals=[self.xml1_vals, self.xml2_vals], expected_invoices={ 1: {'invoice1.xml': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, 2: {'invoice2.xml': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}}, }, ) def test_44_mail_alias_xmls(self): self.assert_attachment_import( origin='mail_alias', attachments_vals=[self.xml1_vals, self.xml2_vals], expected_invoices={ 1: {'invoice1.xml': {'on_message': True, 'is_decoded': True, 'is_new': True}}, 2: {'invoice2.xml': {'on_message': True, 'is_decoded': True, 'is_new': True}}, }, ) def test_50_chatter_upload_embedded_pdf(self): self.assert_attachment_import( origin='chatter_upload', attachments_vals=[self.pdf3_vals, self.pdf2_vals], expected_invoices={ 1: { 'embedded.xml': {'is_decoded': True}, 'invoice3.pdf': {'on_invoice': True}, 'invoice2.pdf': {'on_invoice': True}, }, }, ) def test_51_chatter_message_embedded_pdf(self): self.assert_attachment_import( origin='chatter_message', attachments_vals=[self.pdf3_vals, self.pdf2_vals], expected_invoices={ 1: { 'embedded.xml': {'is_decoded': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, 'invoice2.pdf': {'on_invoice': True, 'on_message': True}, }, }, ) def test_52_chatter_email_embedded_pdf(self): self.assert_attachment_import( origin='chatter_email', attachments_vals=[self.pdf3_vals, self.pdf2_vals], expected_invoices={ 1: { 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, 'invoice2.pdf': {'on_invoice': True, 'on_message': True}, }, }, ) def test_53_journal_upload_embedded_pdf(self): self.assert_attachment_import( origin='journal', attachments_vals=[self.pdf3_vals, self.pdf2_vals], expected_invoices={ 1: { 'embedded.xml': {'is_decoded': True, 'is_new': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, }, 2: { 'invoice2.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}, }, }, ) def test_54_mail_alias_embedded_pdf(self): self.assert_attachment_import( origin='mail_alias', attachments_vals=[self.pdf3_vals, self.pdf2_vals], expected_invoices={ 1: { 'embedded.xml': {'is_decoded': True, 'is_new': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, }, 2: { 'invoice2.pdf': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}, }, }, ) def test_60_chatter_upload_embedded_pdf_and_xml(self): self.assert_attachment_import( origin='chatter_upload', attachments_vals=[self.pdf3_vals, self.xml1_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_invoice': True, 'is_decoded': True}, 'invoice3.pdf': {'on_invoice': True}, }, }, ) def test_61_chatter_message_embedded_pdf_and_xml(self): self.assert_attachment_import( origin='chatter_message', attachments_vals=[self.pdf3_vals, self.xml1_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_message': True, 'is_decoded': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, }, }, ) def test_62_chatter_email_embedded_pdf_and_xml(self): self.assert_attachment_import( origin='chatter_email', attachments_vals=[self.pdf3_vals, self.xml1_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_message': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, }, }, ) def test_63_journal_upload_embedded_pdf_and_xml(self): self.assert_attachment_import( origin='journal', attachments_vals=[self.pdf3_vals, self.xml1_vals], expected_invoices={ 1: { 'embedded.xml': {'is_decoded': True, 'is_new': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, }, 2: { 'invoice1.xml': {'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True}, }, }, ) def test_64_mail_alias_embedded_pdf_and_xml(self): self.assert_attachment_import( origin='mail_alias', attachments_vals=[self.pdf3_vals, self.xml1_vals], expected_invoices={ 1: { 'invoice1.xml': {'on_message': True, 'is_decoded': True, 'is_new': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, }, }, ) def test_70_chatter_upload_all(self): self.assert_attachment_import( origin='chatter_upload', attachments_vals=self.all_attachment_vals, expected_invoices={ 1: { 'invoice2.docx': {'on_invoice': True}, 'gif1.gif': {'on_invoice': True}, 'gif2.gif': {'on_invoice': True}, 'invoice1.pdf': {'on_invoice': True}, 'invoice2.pdf': {'on_invoice': True}, 'invoice3.pdf': {'on_invoice': True}, 'invoice2.xlsx': {'on_invoice': True}, # The code doesn't put a hard constraint on which of the XMLs gets decoded. 'invoice1.xml': {'is_decoded': True, 'on_invoice': True}, 'invoice2.xml': {'on_invoice': True} }, }, ) def test_71_chatter_message_all(self): self.assert_attachment_import( origin='chatter_message', attachments_vals=self.all_attachment_vals, expected_invoices={ 1: { 'invoice2.docx': {'on_invoice': True, 'on_message': True}, 'gif1.gif': {'on_message': True}, 'gif2.gif': {'on_message': True}, 'invoice1.pdf': {'on_invoice': True, 'on_message': True}, 'invoice2.pdf': {'on_invoice': True, 'on_message': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, 'invoice2.xlsx': {'on_invoice': True, 'on_message': True}, # The code doesn't put a hard constraint on which of the XMLs gets decoded. 'invoice1.xml': {'is_decoded': True, 'on_message': True}, 'invoice2.xml': {'on_message': True}, }, }, ) def test_72_chatter_email_all(self): self.assert_attachment_import( origin='chatter_email', attachments_vals=self.all_attachment_vals, expected_invoices={ 1: { 'invoice2.docx': {'on_invoice': True, 'on_message': True}, 'gif1.gif': {'on_message': True}, 'gif2.gif': {'on_message': True}, 'invoice1.pdf': {'on_invoice': True, 'on_message': True}, 'invoice2.pdf': {'on_invoice': True, 'on_message': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, 'invoice2.xlsx': {'on_invoice': True, 'on_message': True}, 'invoice1.xml': {'on_message': True}, 'invoice2.xml': {'on_message': True}, }, }, ) def test_73_journal_upload_all(self): self.assert_attachment_import( origin='journal', attachments_vals=self.all_attachment_vals, expected_invoices={ 1: {'invoice1.pdf': {'is_decoded': True, 'is_new': True, 'on_invoice': True, 'on_message': True}}, 2: {'invoice2.pdf': {'is_decoded': True, 'is_new': True, 'on_invoice': True, 'on_message': True}}, 3: { 'embedded.xml': {'is_decoded': True, 'is_new': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, }, 4: {'gif1.gif': {'on_invoice': True, 'on_message': True}}, 5: {'gif2.gif': {'on_invoice': True, 'on_message': True}}, 6: {'invoice1.xml': {'is_decoded': True, 'is_new': True, 'on_invoice': True, 'on_message': True}}, 7: {'invoice2.xml': {'is_decoded': True, 'is_new': True, 'on_invoice': True, 'on_message': True}}, 8: {'invoice2.docx': {'on_invoice': True, 'on_message': True}}, 9: {'invoice2.xlsx': {'on_invoice': True, 'on_message': True}}, }, ) def test_74_mail_alias_all(self): self.assert_attachment_import( origin='mail_alias', attachments_vals=self.all_attachment_vals, expected_invoices={ 1: { 'gif1.gif': {'on_message': True}, 'gif2.gif': {'on_message': True}, 'invoice1.pdf': {'on_invoice': True, 'on_message': True}, 'invoice1.xml': {'is_decoded': True, 'is_new': True, 'on_message': True}, }, 2: { 'invoice2.pdf': {'on_invoice': True, 'on_message': True}, 'invoice2.xml': {'is_decoded': True, 'is_new': True, 'on_message': True}, # The XLSX and DOCX are attached to this invoice due to filename similarity 'invoice2.xlsx': {'on_invoice': True, 'on_message': True}, 'invoice2.docx': {'on_invoice': True, 'on_message': True}, }, 3: { 'embedded.xml': {'is_decoded': True, 'is_new': True}, 'invoice3.pdf': {'on_invoice': True, 'on_message': True}, } }, ) def test_import_with_traceback(self): # Verify that even an Exception does not cause the import to fail, and that we log the attachment in the chatter attachment = self.env['ir.attachment'].create(self.xml1_vals) with ( self._patch_import_methods(), patch('odoo.addons.account.models.partner.ResPartner.search', side_effect=ValueError('We want to test an unexpected error')), mute_logger('odoo.addons.account.models.account_document_import_mixin'), ): move_id = self.journal.create_document_from_attachment(attachment.ids).get('res_id') self.assertEqual(self.env['account.move'].browse(move_id).attachment_ids, attachment) def test_import_xml_with_embedded_pdf(self): with file_open("account/tests/test_files/xml_with_embedded_pdf.xml", 'rb') as file: xml_vals = {'name': 'invoice.xml', 'raw': file.read(), 'mimetype': 'application/xml'} self.assert_attachment_import( origin='journal', attachments_vals=[xml_vals], expected_invoices={ 1: { 'invoice.xml': { 'on_invoice': True, 'on_message': True, 'is_decoded': True, 'is_new': True, }, 'test_pdf.pdf': { 'on_invoice': True, 'on_message': True, }, }, }, ) self.assert_attachment_import( origin='mail_alias', attachments_vals=[xml_vals], expected_invoices={ 1: { 'invoice.xml': { 'on_message': True, 'is_decoded': True, 'is_new': True, }, 'test_pdf.pdf': { 'on_invoice': True, 'on_message': True, }, }, }, )