[IMP] account: Reversal on same journal type as original AccountMove

For data quality purposes and bug prevention, when I reverse an entry,
the reversal should always be postable on a journal having the same type
as the initial Journal Entry's journal.

closes odoo/odoo#72431

Task: 2497529
Related: odoo/enterprise#19543
Signed-off-by: Laurent Smet <smetl@users.noreply.github.com>
This commit is contained in:
jbw
2021-07-13 10:00:38 +00:00
parent 01063d44cc
commit 6adaec714a
7 changed files with 62 additions and 11 deletions
@@ -1141,6 +1141,7 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon):
'date': fields.Date.from_string('2019-02-01'),
'reason': 'no reason',
'refund_method': 'refund',
'journal_id': self.invoice.journal_id.id,
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
@@ -1192,6 +1193,7 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon):
'date': fields.Date.from_string('2019-02-01'),
'reason': 'no reason again',
'refund_method': 'cancel',
'journal_id': self.invoice.journal_id.id,
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
@@ -1255,6 +1257,7 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon):
'date': fields.Date.from_string('2017-01-01'),
'reason': 'no reason',
'refund_method': 'refund',
'journal_id': self.invoice.journal_id.id,
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
@@ -1312,6 +1315,7 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon):
'date': fields.Date.from_string('2017-01-01'),
'reason': 'no reason again',
'refund_method': 'cancel',
'journal_id': self.invoice.journal_id.id,
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
@@ -1746,6 +1746,7 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
'date': fields.Date.from_string('2019-02-01'),
'reason': 'no reason',
'refund_method': 'refund',
'journal_id': self.invoice.journal_id.id,
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
@@ -1798,6 +1799,7 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
'date': fields.Date.from_string('2019-02-01'),
'reason': 'no reason',
'refund_method': 'cancel',
'journal_id': self.invoice.journal_id.id,
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
@@ -1861,6 +1863,7 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
'date': fields.Date.from_string('2017-01-01'),
'reason': 'no reason',
'refund_method': 'refund',
'journal_id': self.invoice.journal_id.id,
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
@@ -1918,6 +1921,7 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
'date': fields.Date.from_string('2017-01-01'),
'reason': 'no reason',
'refund_method': 'cancel',
'journal_id': self.invoice.journal_id.id,
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
@@ -1978,6 +1982,7 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
'date': fields.Date.today() + timedelta(days=7),
'reason': 'no reason',
'refund_method': 'modify',
'journal_id': self.invoice.journal_id.id,
})
move_reversal.reverse_moves()
refund = self.env['account.move'].search([('move_type', '=', 'out_refund'), ('company_id', '=', self.invoice.company_id.id)])
+38 -2
View File
@@ -26,14 +26,50 @@ class AccountMoveReversal(models.TransientModel):
('modify', 'Full refund and new draft invoice')
], 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.', check_company=True)
journal_id = fields.Many2one(
comodel_name='account.journal',
string='Use Specific Journal',
required=True,
compute='_compute_journal_id',
readonly=False,
store=True,
check_company=True,
help='If empty, uses the journal of the journal entry to be reversed.',
)
company_id = fields.Many2one('res.company', required=True, readonly=True)
available_journal_ids = fields.Many2many('account.journal', compute='_compute_available_journal_ids')
# 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.depends('move_ids')
def _compute_journal_id(self):
for record in self:
if record.journal_id:
record.journal_id = record.journal_id
else:
journals = record.move_ids.journal_id.filtered(lambda x: x.active)
record.journal_id = journals[0] if journals else None
@api.depends('move_ids')
def _compute_available_journal_ids(self):
for record in self:
if record.move_ids:
record.available_journal_ids = self.env['account.journal'].search([
('company_id', '=', record.company_id.id),
('type', 'in', record.move_ids.journal_id.mapped('type')),
])
else:
record.available_journal_ids = self.env['account.journal'].search([('company_id', '=', record.company_id.id)])
@api.constrains('journal_id', 'move_ids')
def _check_journal_type(self):
for record in self:
if record.journal_id.type not in record.move_ids.journal_id.mapped('type'):
raise UserError(_('Journal should be of type of reversed entry.'))
@api.model
def default_get(self, fields):
res = super(AccountMoveReversal, self).default_get(fields)
@@ -65,7 +101,7 @@ class AccountMoveReversal(models.TransientModel):
else _('Reversal of: %s', move.name),
'date': reverse_date,
'invoice_date': move.is_invoice(include_receipts=True) and (self.date or move.date) or False,
'journal_id': self.journal_id and self.journal_id.id or move.journal_id.id,
'journal_id': self.journal_id.id,
'invoice_payment_term_id': None,
'invoice_user_id': move.invoice_user_id.id,
'auto_post': True if reverse_date > fields.Date.context_today(self) else False,
@@ -10,6 +10,7 @@
<field name="company_id" invisible="1"/>
<field name="move_ids" invisible="1"/>
<field name="move_type" invisible="1"/>
<field name="available_journal_ids" invisible="1"/>
<group>
<group attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'in_invoice'))]}">
<field name="refund_method" widget="radio" attrs="{'readonly': [('residual', '=', 0)]}"/>
@@ -28,15 +29,15 @@
</group>
</group>
<group>
<group>
<field name="reason" attrs="{'invisible': [('move_type', '=', 'entry')]}"/>
<field name="date_mode" string="Reversal Date" widget="radio"/>
</group>
<group>
<field name="journal_id"/>
<field name="date" string="Refund Date" attrs="{'invisible': ['|', ('move_type', 'not in', ('out_invoice', 'in_invoice')), ('date_mode', '!=', 'custom')], 'required':[('date_mode', '=', 'custom')]}"/>
<field name="date" attrs="{'invisible': ['|', ('move_type', 'in', ('out_invoice', 'in_invoice')), ('date_mode', '!=', 'custom')], 'required':[('date_mode', '=', 'custom')]}"/>
</group>
<group>
<field name="reason" attrs="{'invisible': [('move_type', '=', 'entry')]}"/>
<field name="date_mode" string="Reversal Date" widget="radio"/>
</group>
<group>
<field name="journal_id" domain="[('id', 'in', available_journal_ids)]"/>
<field name="date" string="Refund Date" attrs="{'invisible': ['|', ('move_type', 'not in', ('out_invoice', 'in_invoice')), ('date_mode', '!=', 'custom')], 'required':[('date_mode', '=', 'custom')]}"/>
<field name="date" attrs="{'invisible': ['|', ('move_type', 'in', ('out_invoice', 'in_invoice')), ('date_mode', '!=', 'custom')], 'required':[('date_mode', '=', 'custom')]}"/>
</group>
</group>
<footer>
<button string='Reverse' name="reverse_moves" type="object" class="btn-primary"/>
@@ -109,6 +109,7 @@ class TestValuationReconciliation(ValuationReconciliationTestCommon):
'reason': 'test_invoice_shipment_refund',
'refund_method': 'cancel',
'date': '2018-03-15',
'journal_id': invoice.journal_id.id,
})
refund_invoice = self.env['account.move'].browse(refund_invoice_wiz.reverse_moves()['res_id'])
+3
View File
@@ -100,6 +100,7 @@ class TestSaleToInvoice(TestSaleCommon):
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',
'journal_id': self.invoice.journal_id.id,
})
credit_note_wizard.reverse_moves()
invoice_refund = self.sale_order.invoice_ids.sorted(key=lambda inv: inv.id, reverse=False)[-1] # the first invoice, its refund, and the new invoice
@@ -191,6 +192,7 @@ class TestSaleToInvoice(TestSaleCommon):
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',
'journal_id': self.invoice.journal_id.id,
})
invoice_refund = self.env['account.move'].browse(credit_note_wizard.reverse_moves()['res_id'])
@@ -253,6 +255,7 @@ class TestSaleToInvoice(TestSaleCommon):
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',
'journal_id': self.invoice.journal_id.id,
})
invoice_refund = self.env['account.move'].browse(credit_note_wizard.reverse_moves()['res_id'])
@@ -115,6 +115,7 @@ class TestValuationReconciliation(ValuationReconciliationTestCommon):
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',
'journal_id': invoice.journal_id.id,
})
refund_invoice = self.env['account.move'].browse(refund_invoice_wiz.reverse_moves()['res_id'])
self.assertEqual(invoice.payment_state, 'reversed', "Invoice should be in 'reversed' state.")