[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:
wan
2019-10-11 17:42:20 +00:00
committed by fw-bot
parent 85785187e6
commit 775b1156e3
8 changed files with 52 additions and 39 deletions
@@ -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',
+27 -20
View File
@@ -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',
+3 -3
View File
@@ -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',
})