diff --git a/account_advanced_protection_features/models/account_move.py b/account_advanced_protection_features/models/account_move.py index ebb091d..029d108 100644 --- a/account_advanced_protection_features/models/account_move.py +++ b/account_advanced_protection_features/models/account_move.py @@ -5,11 +5,12 @@ class AccountMove(models.Model): _inherit = 'account.move' def button_draft(self): - if self.is_move_sent and self.journal_id.prevent_reset_to_draft_sent_invoice: - raise UserError(_( - "You cannot reset to draft this invoice because it has been sent by email." - )) - return super(AccountMove, self).button_draft() + for move in self: + if move.is_move_sent and move.journal_id.prevent_reset_to_draft_sent_invoice: + raise UserError(_( + "You cannot reset to draft this invoice because it has been sent by email." + )) + return super().button_draft() @api.ondelete(at_uninstall=False) def _check_posted(self): diff --git a/account_advanced_protection_features/tests/__init__.py b/account_advanced_protection_features/tests/__init__.py new file mode 100644 index 0000000..f15da20 --- /dev/null +++ b/account_advanced_protection_features/tests/__init__.py @@ -0,0 +1 @@ +from . import test_account_move diff --git a/account_advanced_protection_features/tests/test_account_move.py b/account_advanced_protection_features/tests/test_account_move.py new file mode 100644 index 0000000..77aceda --- /dev/null +++ b/account_advanced_protection_features/tests/test_account_move.py @@ -0,0 +1,53 @@ +# Copyright 2025 Boris Gallet, Clément Thomas, Quentin Mondot +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + +class TestAccountMoveButtonDraft(TransactionCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.partner = cls.env["res.partner"].create({"name": "Test Partner"}) + cls.journal = cls.env["account.journal"].search( + [("type", "=", "sale")], limit=1 + ) + cls.account = cls.env["account.account"].search( + [("account_type", "=", "income")], limit=1 + ) + + def _create_invoice(self): + return self.env["account.move"].create({ + "move_type": "out_invoice", + "partner_id": self.partner.id, + "journal_id": self.journal.id, + "invoice_line_ids": [ + (0, 0, { + "name": "Test line", + "quantity": 1, + "price_unit": 100.0, + "account_id": self.account.id, + }), + ], + }) + + def test_button_draft_multiple_moves(self): + """Test that button_draft works on multiple account.move records. + """ + # Create two invoices + invoice1 = self._create_invoice() + invoice2 = self._create_invoice() + + # Post both invoices + invoice1.action_post() + invoice2.action_post() + + # Combine them into a recordset + invoices = invoice1 | invoice2 + + # This should not raise "Expected singleton" error + invoices.button_draft() + + # Verify both are back to draft + self.assertEqual(invoice1.state, "draft") + self.assertEqual(invoice2.state, "draft")