[FIX] account: allow to reverse multiple moves at the same time again
The way the active_id(s) were retrieved made the wizard only take care of one active_id. This prevented from reverse multiple invoices at the same time. closes odoo/odoo#38537 Fixes: #35759 X-original-commit: fe47011c3fdcec0bda5334f10679e853fe41e45a Signed-off-by: Quentin De Paoli (qdp) <qdp@openerp.com>
This commit is contained in:
@@ -855,7 +855,7 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
|
||||
def test_in_invoice_create_refund(self):
|
||||
self.invoice.post()
|
||||
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
|
||||
'date': fields.Date.from_string('2019-02-01'),
|
||||
'reason': 'no reason',
|
||||
'refund_method': 'refund',
|
||||
@@ -900,7 +900,7 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
|
||||
'invoice_payment_state': 'not_paid',
|
||||
})
|
||||
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
|
||||
'date': fields.Date.from_string('2019-02-01'),
|
||||
'reason': 'no reason again',
|
||||
'refund_method': 'cancel',
|
||||
@@ -957,7 +957,7 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
|
||||
self.invoice.post()
|
||||
|
||||
# The currency rate changed from 1/3 to 1/2.
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
|
||||
'date': fields.Date.from_string('2017-01-01'),
|
||||
'reason': 'no reason',
|
||||
'refund_method': 'refund',
|
||||
@@ -1013,7 +1013,7 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
|
||||
'invoice_payment_state': 'not_paid',
|
||||
})
|
||||
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
|
||||
'date': fields.Date.from_string('2017-01-01'),
|
||||
'reason': 'no reason again',
|
||||
'refund_method': 'cancel',
|
||||
|
||||
@@ -840,7 +840,7 @@ class TestAccountMoveOutInvoiceOnchanges(InvoiceTestCommon):
|
||||
def test_out_invoice_create_refund(self):
|
||||
self.invoice.post()
|
||||
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
|
||||
'date': fields.Date.from_string('2019-02-01'),
|
||||
'reason': 'no reason',
|
||||
'refund_method': 'refund',
|
||||
@@ -886,7 +886,7 @@ class TestAccountMoveOutInvoiceOnchanges(InvoiceTestCommon):
|
||||
'invoice_payment_state': 'not_paid',
|
||||
})
|
||||
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
|
||||
'date': fields.Date.from_string('2019-02-01'),
|
||||
'reason': 'no reason',
|
||||
'refund_method': 'cancel',
|
||||
@@ -943,7 +943,7 @@ class TestAccountMoveOutInvoiceOnchanges(InvoiceTestCommon):
|
||||
self.invoice.post()
|
||||
|
||||
# The currency rate changed from 1/3 to 1/2.
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
|
||||
'date': fields.Date.from_string('2017-01-01'),
|
||||
'reason': 'no reason',
|
||||
'refund_method': 'refund',
|
||||
@@ -999,7 +999,7 @@ class TestAccountMoveOutInvoiceOnchanges(InvoiceTestCommon):
|
||||
'invoice_payment_state': 'not_paid',
|
||||
})
|
||||
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
|
||||
move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({
|
||||
'date': fields.Date.from_string('2017-01-01'),
|
||||
'reason': 'no reason',
|
||||
'refund_method': 'cancel',
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools.translate import _
|
||||
|
||||
|
||||
@@ -11,17 +10,7 @@ class AccountMoveReversal(models.TransientModel):
|
||||
_name = 'account.move.reversal'
|
||||
_description = 'Account Move Reversal'
|
||||
|
||||
@api.model
|
||||
def _get_default_move(self):
|
||||
if self._context.get('active_id'):
|
||||
move = self.env['account.move'].browse(self._context['active_id'])
|
||||
if move.state != 'posted' or move.type in ('out_refund', 'in_refund'):
|
||||
raise UserError(_('Only posted journal entries being not already a refund can be reversed.'))
|
||||
return move
|
||||
return self.env['account.move']
|
||||
|
||||
move_id = fields.Many2one('account.move', string='Journal Entry',
|
||||
default=lambda self: self._get_default_move(),
|
||||
domain=[('state', '=', 'posted'), ('type', 'not in', ('out_refund', 'in_refund'))])
|
||||
date = fields.Date(string='Reversal date', default=fields.Date.context_today, required=True)
|
||||
reason = fields.Char(string='Reason')
|
||||
@@ -29,17 +18,35 @@ class AccountMoveReversal(models.TransientModel):
|
||||
('refund', 'Partial Refund'),
|
||||
('cancel', 'Full Refund'),
|
||||
('modify', 'Full refund and new draft invoice')
|
||||
], default='refund', string='Credit Method', required=True,
|
||||
], string='Credit Method', required=True,
|
||||
help='Choose how you want to credit this invoice. You cannot "modify" nor "cancel" if the invoice is already reconciled.')
|
||||
journal_id = fields.Many2one('account.journal', string='Use Specific Journal', help='If empty, uses the journal of the journal entry to be reversed.')
|
||||
|
||||
# related fields
|
||||
residual = fields.Monetary(related='move_id.amount_residual')
|
||||
currency_id = fields.Many2one(related='move_id.currency_id')
|
||||
move_type = fields.Selection(related='move_id.type')
|
||||
# computed fields
|
||||
residual = fields.Monetary(compute="_compute_from_moves")
|
||||
currency_id = fields.Many2one('res.currency', compute="_compute_from_moves")
|
||||
move_type = fields.Char(compute="_compute_from_moves")
|
||||
|
||||
@api.model
|
||||
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']
|
||||
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')
|
||||
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:
|
||||
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
|
||||
|
||||
def reverse_moves(self):
|
||||
moves = self.move_id or self.env['account.move'].browse(self._context['active_ids'])
|
||||
moves = self.env['account.move'].browse(self.env.context['active_ids']) if self.env.context.get('active_model') == 'account.move' else self.move_id
|
||||
|
||||
# Create default values.
|
||||
default_values_list = []
|
||||
@@ -53,17 +60,17 @@ class AccountMoveReversal(models.TransientModel):
|
||||
})
|
||||
|
||||
# Handle reverse method.
|
||||
if self.refund_method == 'cancel' or (moves and moves[0].type == 'entry'):
|
||||
if self.refund_method == 'cancel':
|
||||
new_moves = moves._reverse_moves(default_values_list, cancel=True)
|
||||
elif self.refund_method == 'modify':
|
||||
new_moves = moves._reverse_moves(default_values_list, cancel=True)
|
||||
moves._reverse_moves(default_values_list, cancel=True)
|
||||
moves_vals_list = []
|
||||
for move in moves.with_context(include_business_fields=True):
|
||||
moves_vals_list.append(move.copy_data({
|
||||
'invoice_payment_ref': move.name,
|
||||
'date': self.date or move.date,
|
||||
})[0])
|
||||
new_moves = moves.create(moves_vals_list)
|
||||
new_moves = self.env['account.move'].create(moves_vals_list)
|
||||
elif self.refund_method == 'refund':
|
||||
new_moves = moves._reverse_moves(default_values_list)
|
||||
else:
|
||||
|
||||
@@ -8,11 +8,6 @@
|
||||
<form string="Reverse Journal Entry">
|
||||
<field name="residual" invisible="1"/>
|
||||
<field name="move_type" invisible="1"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="move_id" readonly="context.get('active_id')" invisible="context.get('active_id')" />
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'in_invoice'))]}">
|
||||
<field name="refund_method" widget="radio" attrs="{'readonly': [('residual', '=', 0)]}"/>
|
||||
@@ -37,7 +32,7 @@
|
||||
<field name="date" attrs="{'invisible': [('move_type', 'in', ('out_invoice', 'in_invoice'))]}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="journal_id" attrs="{'invisible': [('move_type', 'not in', ('entry'))]}" />
|
||||
<field name="journal_id"/>
|
||||
</group>
|
||||
</group>
|
||||
<footer>
|
||||
|
||||
@@ -14,6 +14,17 @@ class AccountMoveReversal(models.TransientModel):
|
||||
l10n_latam_sequence_id = fields.Many2one('ir.sequence', compute='_compute_l10n_latam_sequence')
|
||||
l10n_latam_document_number = fields.Char(string='Document Number')
|
||||
|
||||
@api.model
|
||||
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 len(move_ids) > 1:
|
||||
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')))
|
||||
|
||||
return res
|
||||
|
||||
@staticmethod
|
||||
def _reverse_type_map(move_type):
|
||||
match = {
|
||||
|
||||
@@ -130,7 +130,7 @@ class TestValuationReconciliation(ValuationReconciliationTestCase):
|
||||
})
|
||||
|
||||
# Refund the invoice
|
||||
refund_invoice_wiz = self.env['account.move.reversal'].with_context(active_ids=[invoice.id]).create({
|
||||
refund_invoice_wiz = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=[invoice.id]).create({
|
||||
'reason': 'test_invoice_shipment_refund',
|
||||
'refund_method': 'cancel',
|
||||
'date': '2018-03-15',
|
||||
|
||||
@@ -100,7 +100,7 @@ class TestSaleToInvoice(TestCommonSaleNoChart):
|
||||
self.assertEqual(len(line.invoice_lines), 1, "The lines 'ordered' qty are invoiced, so it should be linked to 1 invoice lines")
|
||||
|
||||
# Make a credit note
|
||||
credit_note_wizard = self.env['account.move.reversal'].with_context({'active_ids': [self.invoice.id], 'active_id': self.invoice.id}).create({
|
||||
credit_note_wizard = self.env['account.move.reversal'].with_context({'active_ids': [self.invoice.id], 'active_id': self.invoice.id, 'active_model': 'account.move'}).create({
|
||||
'refund_method': 'refund', # this is the only mode for which the SO line is linked to the refund (https://github.com/odoo/odoo/commit/e680f29560ac20133c7af0c6364c6ef494662eac)
|
||||
'reason': 'reason test create',
|
||||
})
|
||||
@@ -191,7 +191,7 @@ class TestSaleToInvoice(TestCommonSaleNoChart):
|
||||
self.assertEqual(line.qty_to_invoice, -1, "The quantity to invoice is negative as we invoice more than ordered")
|
||||
|
||||
# Make a credit note
|
||||
credit_note_wizard = self.env['account.move.reversal'].with_context({'active_ids': self.invoice.ids, 'active_id': self.invoice.id}).create({
|
||||
credit_note_wizard = self.env['account.move.reversal'].with_context({'active_ids': self.invoice.ids, 'active_id': self.invoice.id, 'active_model': 'account.move'}).create({
|
||||
'refund_method': 'cancel',
|
||||
'reason': 'reason test cancel',
|
||||
})
|
||||
@@ -253,7 +253,7 @@ class TestSaleToInvoice(TestCommonSaleNoChart):
|
||||
self.assertEqual(len(line.invoice_lines), 1, "The lines 'ordered' qty are invoiced, so it should be linked to 1 invoice lines")
|
||||
|
||||
# Make a credit note
|
||||
credit_note_wizard = self.env['account.move.reversal'].with_context({'active_ids': [self.invoice.id], 'active_id': self.invoice.id}).create({
|
||||
credit_note_wizard = self.env['account.move.reversal'].with_context({'active_ids': [self.invoice.id], 'active_id': self.invoice.id, 'active_model': 'account.move'}).create({
|
||||
'refund_method': 'modify', # this is the only mode for which the SO line is linked to the refund (https://github.com/odoo/odoo/commit/e680f29560ac20133c7af0c6364c6ef494662eac)
|
||||
'reason': 'reason test modify',
|
||||
})
|
||||
|
||||
@@ -152,7 +152,7 @@ class TestValuationReconciliation(ValuationReconciliationTestCase):
|
||||
'rate': 9.56564564,
|
||||
'name': '2018-04-01',
|
||||
})
|
||||
refund_invoice_wiz = self.env['account.move.reversal'].with_context(active_ids=[invoice.id]).create({
|
||||
refund_invoice_wiz = self.env['account.move.reversal'].with_context(active_model='account.move', active_ids=[invoice.id]).create({
|
||||
'reason': 'test_invoice_shipment_refund',
|
||||
'refund_method': 'cancel',
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user