diff --git a/addons/account/tests/test_reconciliation.py b/addons/account/tests/test_reconciliation.py index bb56e66e826..d04e641f100 100644 --- a/addons/account/tests/test_reconciliation.py +++ b/addons/account/tests/test_reconciliation.py @@ -1626,7 +1626,7 @@ class TestReconciliationExec(TestAccountReconciliationCommon): reverse_date = fields.Date.today() + timedelta(days=+7) revertWidget = self.env['account.move.reversal'].create({ - 'move_id': purchase_move.id, + 'move_ids': [(6, 0, [purchase_move.id])], 'date': reverse_date, 'reason': ['cancel'], }) diff --git a/addons/account/wizard/account_move_reversal.py b/addons/account/wizard/account_move_reversal.py index d51de2a7e69..67683ac44b5 100644 --- a/addons/account/wizard/account_move_reversal.py +++ b/addons/account/wizard/account_move_reversal.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from odoo import models, fields, api from odoo.tools.translate import _ +from odoo.exceptions import UserError class AccountMoveReversal(models.TransientModel): @@ -10,9 +11,8 @@ class AccountMoveReversal(models.TransientModel): _name = 'account.move.reversal' _description = 'Account Move Reversal' - move_id = fields.Many2one('account.move', string='Journal Entry', - domain=[('state', '=', 'posted'), ('type', 'not in', ('out_refund', 'in_refund'))]) - new_move_ids = fields.Many2many('account.move') + move_ids = fields.Many2many('account.move', 'account_move_reversal_move', 'reversal_id', 'move_id', domain=[('state', '=', 'posted')]) + new_move_ids = fields.Many2many('account.move', 'account_move_reversal_new_move', 'reversal_id', 'new_move_id') date = fields.Date(string='Reversal date', default=fields.Date.context_today, required=True) reason = fields.Char(string='Reason') refund_method = fields.Selection(selection=[ @@ -32,22 +32,23 @@ class AccountMoveReversal(models.TransientModel): def default_get(self, fields): res = super(AccountMoveReversal, self).default_get(fields) move_ids = self.env['account.move'].browse(self.env.context['active_ids']) if self.env.context.get('active_model') == 'account.move' else self.env['account.move'] + if any(move.state != "posted" for move in move_ids): + raise UserError(_('You can only reverse posted moves.')) + res['move_ids'] = [(6, 0, move_ids.ids)] res['refund_method'] = (len(move_ids) > 1 or move_ids.type == 'entry') and 'cancel' or 'refund' - res['residual'] = len(move_ids) == 1 and move_ids.amount_residual or 0 - res['currency_id'] = len(move_ids.currency_id) == 1 and move_ids.currency_id.id or False - res['move_type'] = len(move_ids) == 1 and move_ids.type or False return res - @api.depends('move_id') + @api.depends('move_ids') def _compute_from_moves(self): - move_ids = self.env['account.move'].browse(self.env.context['active_ids']) if self.env.context.get('active_model') == 'account.move' else self.move_id for record in self: + move_ids = record.move_ids record.residual = len(move_ids) == 1 and move_ids.amount_residual or 0 record.currency_id = len(move_ids.currency_id) == 1 and move_ids.currency_id or False - record.move_type = len(move_ids) == 1 and move_ids.type or False + record.move_type = move_ids.type if len(move_ids) == 1 else (any(move.type in ('in_invoice', 'out_invoice') for move in move_ids) and 'some_invoice' or False) def reverse_moves(self): - moves = self.env['account.move'].browse(self.env.context['active_ids']) if self.env.context.get('active_model') == 'account.move' else self.move_id + self.ensure_one() + moves = self.move_ids # Create default values. default_values_list = [] diff --git a/addons/account/wizard/account_move_reversal_view.xml b/addons/account/wizard/account_move_reversal_view.xml index be34b07889f..28371f68c90 100644 --- a/addons/account/wizard/account_move_reversal_view.xml +++ b/addons/account/wizard/account_move_reversal_view.xml @@ -7,12 +7,14 @@
+ + Invoices/>Bills won't be reversed but credit notes will be created instead: the tax tags will be adapted accordingly. - +
The credit note is created in draft and can be edited before being issued.
diff --git a/addons/l10n_latam_invoice_document/wizards/account_move_reversal.py b/addons/l10n_latam_invoice_document/wizards/account_move_reversal.py index ae1da9561c2..e6356df2e7e 100644 --- a/addons/l10n_latam_invoice_document/wizards/account_move_reversal.py +++ b/addons/l10n_latam_invoice_document/wizards/account_move_reversal.py @@ -8,8 +8,7 @@ class AccountMoveReversal(models.TransientModel): _inherit = "account.move.reversal" - l10n_latam_use_documents = fields.Boolean( - related='move_id.journal_id.l10n_latam_use_documents', readonly=True) + l10n_latam_use_documents = fields.Boolean(readonly=True) l10n_latam_document_type_id = fields.Many2one('l10n_latam.document.type', 'Document Type', ondelete='cascade') l10n_latam_sequence_id = fields.Many2one('ir.sequence', compute='_compute_l10n_latam_sequence') l10n_latam_document_number = fields.Char(string='Document Number') @@ -22,6 +21,8 @@ class AccountMoveReversal(models.TransientModel): move_ids_use_document = move_ids.filtered(lambda move: move.l10n_latam_use_documents) if move_ids_use_document: raise UserError(_('You can only reverse documents with legal invoicing documents from Latin America one at a time.\nProblematic documents: %s') % ", ".join(move_ids_use_document.mapped('name'))) + else: + res['l10n_latam_use_documents'] = move_ids.journal_id.l10n_latam_use_documents return res @@ -36,14 +37,14 @@ class AccountMoveReversal(models.TransientModel): 'in_receipt': 'out_receipt'} return match.get(move_type) - @api.onchange('move_id') + @api.onchange('move_ids') def _onchange_move_id(self): - if self.move_id.l10n_latam_use_documents: - refund = self.move_id.new({ - 'type': self._reverse_type_map(self.move_id.type), - 'journal_id': self.move_id.journal_id.id, - 'partner_id': self.move_id.partner_id.id, - 'company_id': self.move_id.company_id.id, + if self.l10n_latam_use_documents: + refund = self.env['account.move'].new({ + 'type': self._reverse_type_map(self.move_ids.type), + 'journal_id': self.move_ids.journal_id.id, + 'partner_id': self.move_ids.partner_id.id, + 'company_id': self.move_ids.company_id.id, }) self.l10n_latam_document_type_id = refund.l10n_latam_document_type_id return {'domain': { @@ -57,14 +58,16 @@ class AccountMoveReversal(models.TransientModel): @api.depends('l10n_latam_document_type_id') def _compute_l10n_latam_sequence(self): for rec in self: - refund = rec.move_id.new({ - 'type': self._reverse_type_map(rec.move_id.type), - 'journal_id': rec.move_id.journal_id.id, - 'partner_id': rec.move_id.partner_id.id, - 'company_id': rec.move_id.company_id.id, - 'l10n_latam_document_type_id': rec.l10n_latam_document_type_id.id, - }) - rec.l10n_latam_sequence_id = refund._get_document_type_sequence() + rec.l10n_latam_sequence_id = False + if len(rec.move_ids) <= 1: + refund = rec.env['account.move'].new({ + 'type': self._reverse_type_map(rec.move_ids.type), + 'journal_id': rec.move_ids.journal_id.id, + 'partner_id': rec.move_ids.partner_id.id, + 'company_id': rec.move_ids.company_id.id, + 'l10n_latam_document_type_id': rec.l10n_latam_document_type_id.id, + }) + rec.l10n_latam_sequence_id = refund._get_document_type_sequence() @api.onchange('l10n_latam_document_number', 'l10n_latam_document_type_id') def _onchange_l10n_latam_document_number(self):