From 4d3ac4cbd87fa3db2bf7ac21d729a91eaf52a9be Mon Sep 17 00:00:00 2001 From: "Sohail Jaidi (soja)" Date: Mon, 15 May 2023 13:09:50 +0000 Subject: [PATCH] [IMP] account,*: simplify add credit note wizard Description of the issue/feature this PR addresses: simplification of the credit note wizard Current behavior before commit: First users select reverse option (3 radio buttons): 1) refund 2) cancel 3) modify The reverse action is triggered when the users clicks on the "reverse" button After commit: radio button are removed. There is now two buttons that trigger directly the reverse action with the desired option (refund or modify, cancel is not available anymore) Also, for refund, posting the draft reverse move will also reconcile with reversed move. task id: 3244377 closes odoo/odoo#117961 Related: odoo/enterprise#40919 Related: odoo/upgrade#4667 Signed-off-by: John Laterre (jol) --- addons/account/models/account_move.py | 34 ++++++--- .../tests/test_account_move_date_algorithm.py | 3 +- .../account/tests/test_account_move_entry.py | 3 +- .../tests/test_account_move_in_invoice.py | 18 ++--- .../tests/test_account_move_out_invoice.py | 15 ++-- .../tests/test_account_move_reconcile.py | 6 +- .../account/wizard/account_move_reversal.py | 32 ++++----- .../wizard/account_move_reversal_view.xml | 30 ++------ .../tests/test_sepa_qr.py | 3 +- .../demo/account_customer_refund_demo.xml | 9 +-- .../demo/account_supplier_refund_demo.xml | 9 +-- addons/l10n_ar/tests/common.py | 3 +- .../tests/test_edi_xml.py | 3 +- .../wizard/account_move_reversal.py | 4 +- .../wizards/account_move_reversal_view.xml | 4 +- ...st_anglo_saxon_valuation_reconciliation.py | 3 +- addons/sale/tests/test_sale_refund.py | 70 +------------------ .../test_sale_mrp_anglo_saxon_valuation.py | 3 +- addons/sale_mrp/tests/test_sale_mrp_flow.py | 3 +- .../tests/test_anglo_saxon_valuation.py | 6 +- ...st_anglo_saxon_valuation_reconciliation.py | 3 +- .../tests/test_sale_stock_report.py | 7 +- addons/sale_timesheet/tests/test_reinvoice.py | 3 +- .../tests/test_stockvaluationlayer.py | 3 +- 24 files changed, 83 insertions(+), 194 deletions(-) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index d7d69b46379..f00ac1137bb 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -3342,6 +3342,23 @@ class AccountMove(models.Model): exchange_diff_moves.append(partial.exchange_move_id.id) return invoice_partials, exchange_diff_moves + def _reconcile_reversed_moves(self, reverse_moves, move_reverse_cancel): + ''' Reconciles moves in self and reverse moves + :param move_reverse_cancel: parameter used when lines are reconciled + will determine whether the tax cash basis journal entries should be created + :param reverse_moves: An account.move recordset, reverse of the current self. + :return: An account.move recordset, reverse of the current self. + ''' + for move, reverse_move in zip(self, reverse_moves): + group = (move.line_ids + reverse_move.line_ids) \ + .filtered(lambda l: not l.reconciled) \ + .grouped(lambda l: (l.account_id, l.currency_id)) + for (account, _currency), lines in group.items(): + if account.reconcile or account.account_type in ('asset_cash', 'liability_credit_card'): + lines.with_context(move_reverse_cancel=move_reverse_cancel).reconcile() + return reverse_moves + + def _reverse_moves(self, default_values_list=None, cancel=False): ''' Reverse a recordset of account.move. If cancel parameter is true, the reconcilable or liquidity lines @@ -3383,13 +3400,7 @@ class AccountMove(models.Model): # Reconcile moves together to cancel the previous one. if cancel: reverse_moves.with_context(move_reverse_cancel=cancel)._post(soft=False) - for move, reverse_move in zip(self, reverse_moves): - group = (move.line_ids + reverse_move.line_ids)\ - .filtered(lambda l: not l.reconciled)\ - .grouped(lambda l: (l.account_id, l.currency_id)) - for (account, _currency), lines in group.items(): - if account.reconcile or account.account_type in ('asset_cash', 'liability_credit_card'): - lines.with_context(move_reverse_cancel=cancel).reconcile() + reverse_moves = self._reconcile_reversed_moves(reverse_moves, cancel) return reverse_moves @@ -3456,8 +3467,8 @@ class AccountMove(models.Model): to_post = self for move in to_post: - if move.state == 'posted': - raise UserError(_('The entry %s (id %s) is already posted.') % (move.name, move.id)) + if move.state in ['posted', 'cancel']: + raise UserError(_('The entry %s (id %s) must be in draft.') % (move.name, move.id)) if not move.line_ids.filtered(lambda line: line.display_type not in ('line_section', 'line_note')): raise UserError(_('You need to add a line before posting.')) if move.auto_post != 'no' and move.date > fields.Date.context_today(self): @@ -3498,11 +3509,16 @@ class AccountMove(models.Model): if wrong_lines: wrong_lines.write({'partner_id': invoice.commercial_partner_id.id}) + # reconcile if state is in draft and move has reversal_entry_id set + draft_reverse_moves = to_post.filtered(lambda move: move.reversed_entry_id) + to_post.write({ 'state': 'posted', 'posted_before': True, }) + draft_reverse_moves.reversed_entry_id._reconcile_reversed_moves(draft_reverse_moves, False) + for invoice in to_post: invoice.message_subscribe([ p.id diff --git a/addons/account/tests/test_account_move_date_algorithm.py b/addons/account/tests/test_account_move_date_algorithm.py index c06ec23b45e..8a3ef917b3f 100644 --- a/addons/account/tests/test_account_move_date_algorithm.py +++ b/addons/account/tests/test_account_move_date_algorithm.py @@ -49,9 +49,8 @@ class TestAccountMoveDateAlgorithm(AccountTestInvoicingCommon): .create({ 'journal_id': invoice.journal_id.id, 'reason': "no reason", - 'refund_method': 'cancel', }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.refund_moves() return self.env['account.move'].browse(reversal['res_id']) # ------------------------------------------------------------------------- diff --git a/addons/account/tests/test_account_move_entry.py b/addons/account/tests/test_account_move_entry.py index 8936f78e3d6..d90f9c41626 100644 --- a/addons/account/tests/test_account_move_entry.py +++ b/addons/account/tests/test_account_move_entry.py @@ -606,10 +606,9 @@ class TestAccountMove(AccountTestInvoicingCommon): move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=move.ids).create({ 'date': fields.Date.from_string('2021-02-01'), - 'refund_method': 'refund', 'journal_id': move.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.refund_moves() reversed_move = self.env['account.move'].browse(reversal['res_id']) self.assertRecordValues(reversed_move.line_ids, [ { diff --git a/addons/account/tests/test_account_move_in_invoice.py b/addons/account/tests/test_account_move_in_invoice.py index d98fae1ef34..d7ee2c60633 100644 --- a/addons/account/tests/test_account_move_in_invoice.py +++ b/addons/account/tests/test_account_move_in_invoice.py @@ -1116,10 +1116,9 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 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', 'journal_id': self.invoice.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.refund_moves() reverse_move = self.env['account.move'].browse(reversal['res_id']) self.assertEqual(self.invoice.payment_state, 'not_paid', "Refunding with a draft credit note should keep the invoice 'not_paid'.") @@ -1168,10 +1167,9 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 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': 'modify', 'journal_id': self.invoice.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.modify_moves() new_move = self.env['account.move'].browse(reversal['res_id']) self.assertEqual(self.invoice.payment_state, 'reversed', "After cancelling it with a reverse invoice, an invoice should be in 'reversed' state.") @@ -1231,10 +1229,9 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 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', 'journal_id': self.invoice.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.refund_moves() reverse_move = self.env['account.move'].browse(reversal['res_id']) self.assertEqual(self.invoice.payment_state, 'not_paid', "Refunding with a draft credit note should keep the invoice 'not_paid'.") @@ -1289,10 +1286,9 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): 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': 'modify', 'journal_id': self.invoice.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.modify_moves() new_move = self.env['account.move'].browse(reversal['res_id']) self.assertEqual(self.invoice.payment_state, 'reversed', "After cancelling it with a reverse invoice, an invoice should be in 'reversed' state.") @@ -2182,10 +2178,9 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): .with_context(active_model='account.move', active_ids=move.ids)\ .create({ 'reason': 'no reason', - 'refund_method': 'refund', 'journal_id': move.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.refund_moves() reverse_move = self.env['account.move'].browse(reversal['res_id']) if reverse_move.move_type in ('out_refund', 'in_refund'): reverse_move.write({ @@ -2202,9 +2197,6 @@ class TestAccountMoveInInvoiceOnchanges(AccountTestInvoicingCommon): }) reverse_move.action_post() - (move + reverse_move).line_ids\ - .filtered(lambda line: line.account_type in ('asset_receivable', 'liability_payable'))\ - .reconcile() move = create_move(move_type, amount) line = move.line_ids.filtered(lambda line: line.account_type in ('asset_receivable', 'liability_payable')) diff --git a/addons/account/tests/test_account_move_out_invoice.py b/addons/account/tests/test_account_move_out_invoice.py index 0f0068f8ae9..e350eea5332 100644 --- a/addons/account/tests/test_account_move_out_invoice.py +++ b/addons/account/tests/test_account_move_out_invoice.py @@ -1732,10 +1732,9 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 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', 'journal_id': self.invoice.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.refund_moves() reverse_move = self.env['account.move'].browse(reversal['res_id']) self.assertEqual(self.invoice.payment_state, 'not_paid', "Refunding with a draft credit note should keep the invoice 'not_paid'.") @@ -1785,10 +1784,9 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 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': 'modify', 'journal_id': self.invoice.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.modify_moves() new_move = self.env['account.move'].browse(reversal['res_id']) self.assertEqual(self.invoice.payment_state, 'reversed', "After cancelling it with a reverse invoice, an invoice should be in 'reversed' state.") @@ -1848,10 +1846,9 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 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', 'journal_id': self.invoice.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.refund_moves() reverse_move = self.env['account.move'].browse(reversal['res_id']) self.assertEqual(self.invoice.payment_state, 'not_paid', "Refunding with a draft credit note should keep the invoice 'not_paid'.") @@ -1906,10 +1903,9 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): 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': 'modify', 'journal_id': self.invoice.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.modify_moves() new_move = self.env['account.move'].browse(reversal['res_id']) self.assertEqual(self.invoice.payment_state, 'reversed', "After cancelling it with a reverse invoice, an invoice should be in 'reversed' state.") @@ -1967,10 +1963,9 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon): move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.invoice.ids).create({ 'date': fields.Date.today() + timedelta(days=7), 'reason': 'no reason', - 'refund_method': 'modify', 'journal_id': self.invoice.journal_id.id, }) - move_reversal.reverse_moves() + move_reversal.modify_moves() refund = self.env['account.move'].search([('move_type', '=', 'out_refund'), ('company_id', '=', self.invoice.company_id.id)]) self.assertRecordValues(refund, [{ diff --git a/addons/account/tests/test_account_move_reconcile.py b/addons/account/tests/test_account_move_reconcile.py index 80b5230e517..bf70a2a2f55 100644 --- a/addons/account/tests/test_account_move_reconcile.py +++ b/addons/account/tests/test_account_move_reconcile.py @@ -3835,10 +3835,9 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): .with_context(active_model='account.move', active_ids=invoice.ids)\ .create({ 'reason': "test_reconcile_cash_basis_tax_grid_reversal", - 'refund_method': 'refund', 'journal_id': invoice.journal_id.id, }) - refund = self.env['account.move'].browse(reversal_wizard.reverse_moves()['res_id']) + refund = self.env['account.move'].browse(reversal_wizard.refund_moves()['res_id']) refund.action_post() self.assertRecordValues(refund.line_ids.sorted('balance'), [ @@ -3851,10 +3850,9 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon): .with_context(active_model='account.move', active_ids=refund.ids)\ .create({ 'reason': "test_reconcile_cash_basis_tax_grid_reversal", - 'refund_method': 'refund', 'journal_id': refund.journal_id.id, }) - reversed_refund = self.env['account.move'].browse(reversal_wizard.reverse_moves()['res_id']) + reversed_refund = self.env['account.move'].browse(reversal_wizard.refund_moves()['res_id']) self.assertRecordValues(reversed_refund.line_ids.sorted('balance'), [ {'debit': 0.0, 'credit': 1000.0, 'tax_tag_ids': [], 'account_id': self.company_data['default_account_revenue'].id}, diff --git a/addons/account/wizard/account_move_reversal.py b/addons/account/wizard/account_move_reversal.py index 0ac44a19d09..33bf8eb4695 100644 --- a/addons/account/wizard/account_move_reversal.py +++ b/addons/account/wizard/account_move_reversal.py @@ -14,21 +14,11 @@ class AccountMoveReversal(models.TransientModel): 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_mode = fields.Selection(selection=[ - ('custom', 'Specific'), - ('entry', 'Journal Entry Date') - ], required=True, default='custom') date = fields.Date(string='Reversal date', default=fields.Date.context_today) - reason = fields.Char(string='Reason') - refund_method = fields.Selection(selection=[ - ('refund', 'Partial Refund'), - ('cancel', 'Full Refund'), - ('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.') + reason = fields.Char(string='Reason displayed on Credit Note') journal_id = fields.Many2one( comodel_name='account.journal', - string='Use Specific Journal', + string='Journal', required=True, compute='_compute_journal_id', readonly=False, @@ -82,8 +72,6 @@ class AccountMoveReversal(models.TransientModel): res['company_id'] = move_ids.company_id.id or self.env.company.id if 'move_ids' in fields: res['move_ids'] = [(6, 0, move_ids.ids)] - if 'refund_method' in fields: - res['refund_method'] = (len(move_ids) > 1 or move_ids.move_type == 'entry') and 'cancel' or 'refund' return res @api.depends('move_ids') @@ -95,7 +83,7 @@ class AccountMoveReversal(models.TransientModel): record.move_type = move_ids.move_type if len(move_ids) == 1 else (any(move.move_type in ('in_invoice', 'out_invoice') for move in move_ids) and 'some_invoice' or False) def _prepare_default_reversal(self, move): - reverse_date = self.date if self.date_mode == 'custom' else move.date + reverse_date = self.date return { 'ref': _('Reversal of: %(move_name)s, %(reason)s', move_name=move.name, reason=self.reason) if self.reason @@ -109,7 +97,7 @@ class AccountMoveReversal(models.TransientModel): 'auto_post': 'at_date' if reverse_date > fields.Date.context_today(self) else 'no', } - def reverse_moves(self): + def reverse_moves(self, is_modify=False): self.ensure_one() moves = self.move_ids @@ -124,7 +112,7 @@ class AccountMoveReversal(models.TransientModel): ] for move, default_vals in zip(moves, default_values_list): is_auto_post = default_vals.get('auto_post') != 'no' - is_cancel_needed = not is_auto_post and self.refund_method in ('cancel', 'modify') + is_cancel_needed = not is_auto_post and is_modify batch_index = 0 if is_cancel_needed else 1 batches[batch_index][0] |= move batches[batch_index][1].append(default_vals) @@ -134,10 +122,10 @@ class AccountMoveReversal(models.TransientModel): for moves, default_values_list, is_cancel_needed in batches: new_moves = moves._reverse_moves(default_values_list, cancel=is_cancel_needed) - if self.refund_method == 'modify': + if is_modify: moves_vals_list = [] for move in moves.with_context(include_business_fields=True): - moves_vals_list.append(move.copy_data({'date': self.date if self.date_mode == 'custom' else move.date})[0]) + moves_vals_list.append(move.copy_data({'date': self.date})[0]) new_moves = self.env['account.move'].create(moves_vals_list) moves_to_redirect |= new_moves @@ -164,3 +152,9 @@ class AccountMoveReversal(models.TransientModel): if len(set(moves_to_redirect.mapped('move_type'))) == 1: action['context'] = {'default_move_type': moves_to_redirect.mapped('move_type').pop()} return action + + def refund_moves(self): + return self.reverse_moves(is_modify=False) + + def modify_moves(self): + return self.reverse_moves(is_modify=True) diff --git a/addons/account/wizard/account_move_reversal_view.xml b/addons/account/wizard/account_move_reversal_view.xml index 96652d6f6b6..0ec7eaf035d 100644 --- a/addons/account/wizard/account_move_reversal_view.xml +++ b/addons/account/wizard/account_move_reversal_view.xml @@ -12,35 +12,13 @@ - - - - -
- The credit note is created in draft and can be edited before being issued. -
-
- The credit note is auto-validated and reconciled with the invoice. -
-
- The credit note is auto-validated and reconciled with the invoice. - The original invoice is duplicated as a new draft. -
-
-
- - - - - - + - - - +
-
diff --git a/addons/account_qr_code_sepa/tests/test_sepa_qr.py b/addons/account_qr_code_sepa/tests/test_sepa_qr.py index 1613e60566a..83e31ab8e98 100644 --- a/addons/account_qr_code_sepa/tests/test_sepa_qr.py +++ b/addons/account_qr_code_sepa/tests/test_sepa_qr.py @@ -71,10 +71,9 @@ class TestSEPAQRCode(AccountTestInvoicingCommon): move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=self.sepa_qr_invoice.ids).create({ 'date': fields.Date.from_string('2019-02-01'), 'reason': 'no reason', - 'refund_method': 'refund', 'journal_id': self.sepa_qr_invoice.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.refund_moves() reverse_move = self.env['account.move'].browse(reversal['res_id']) self.assertFalse(reverse_move.qr_code_method, "qr_code_method for credit note should be None") diff --git a/addons/l10n_ar/demo/account_customer_refund_demo.xml b/addons/l10n_ar/demo/account_customer_refund_demo.xml index 3c1366c24de..6ef957ae544 100644 --- a/addons/l10n_ar/demo/account_customer_refund_demo.xml +++ b/addons/l10n_ar/demo/account_customer_refund_demo.xml @@ -4,34 +4,31 @@ Mercadería defectuosa - refund - + Venta cancelada - cancel - + Venta cancelada - cancel - + diff --git a/addons/l10n_ar/demo/account_supplier_refund_demo.xml b/addons/l10n_ar/demo/account_supplier_refund_demo.xml index edf3b0abe54..234449e5a8d 100644 --- a/addons/l10n_ar/demo/account_supplier_refund_demo.xml +++ b/addons/l10n_ar/demo/account_supplier_refund_demo.xml @@ -4,29 +4,26 @@ Mercadería defectuosa - refund 0001-01234567 - + Venta cancelada - cancel 0001-01234566 - + demo_sup_refund_invoice_5: liquido producto bill refund (credit note) - cancel 00011-00000012 @@ -34,6 +31,6 @@ - + diff --git a/addons/l10n_ar/tests/common.py b/addons/l10n_ar/tests/common.py index 2968387f0bd..27531d189a2 100644 --- a/addons/l10n_ar/tests/common.py +++ b/addons/l10n_ar/tests/common.py @@ -699,14 +699,13 @@ class TestAr(AccountTestInvoicingCommon): data = data or {} refund_wizard = self.env['account.move.reversal'].with_context({'active_ids': [invoice.id], 'active_model': 'account.move'}).create({ 'reason': data.get('reason', 'Mercadería defectuosa'), - 'refund_method': data.get('refund_method', 'refund'), 'journal_id': invoice.journal_id.id}) forced_document_type = data.get('document_type') if forced_document_type: refund_wizard.l10n_latam_document_type_id = forced_document_type.id - res = refund_wizard.reverse_moves() + res = refund_wizard.refund_moves() if data.get('refund_method', 'refund') == 'refund' else refund_wizard.modify_moves() refund = self.env['account.move'].browse(res['res_id']) return refund diff --git a/addons/l10n_es_edi_facturae/tests/test_edi_xml.py b/addons/l10n_es_edi_facturae/tests/test_edi_xml.py index c6c07b85b1b..4c0b4528131 100644 --- a/addons/l10n_es_edi_facturae/tests/test_edi_xml.py +++ b/addons/l10n_es_edi_facturae/tests/test_edi_xml.py @@ -207,11 +207,10 @@ class TestEdiFacturaeXmls(AccountEdiTestCommon): 'move_ids': invoice.ids, 'journal_id': invoice.journal_id.id, 'date': self.frozen_today, - 'refund_method': 'modify', 'company_id': self.company_data['company'].id, 'l10n_es_edi_facturae_reason_code': '01' }) - reversal_wizard.reverse_moves() + reversal_wizard.modify_moves() refund = invoice.reversal_move_id generated_file = refund._l10n_es_edi_facturae_render_facturae() self.assertTrue(generated_file) diff --git a/addons/l10n_es_edi_facturae/wizard/account_move_reversal.py b/addons/l10n_es_edi_facturae/wizard/account_move_reversal.py index 21fc498602a..9fcb73d46b7 100644 --- a/addons/l10n_es_edi_facturae/wizard/account_move_reversal.py +++ b/addons/l10n_es_edi_facturae/wizard/account_move_reversal.py @@ -30,8 +30,8 @@ class AccountMoveReversal(models.TransientModel): ('85', 'Taxable income modified by unpaid tax assessments. Order of declaration of bankruptcy'), ], string='Spanish Facturae EDI Reason Code', default='10') - def reverse_moves(self): + def reverse_moves(self, is_modify=False): # Extends account_account - res = super(AccountMoveReversal, self).reverse_moves() + res = super(AccountMoveReversal, self).reverse_moves(is_modify) self.new_move_ids.l10n_es_edi_facturae_reason_code = self.l10n_es_edi_facturae_reason_code return res diff --git a/addons/l10n_latam_invoice_document/wizards/account_move_reversal_view.xml b/addons/l10n_latam_invoice_document/wizards/account_move_reversal_view.xml index 90f7a67a57b..22318049a2c 100644 --- a/addons/l10n_latam_invoice_document/wizards/account_move_reversal_view.xml +++ b/addons/l10n_latam_invoice_document/wizards/account_move_reversal_view.xml @@ -12,8 +12,8 @@ - - + + diff --git a/addons/purchase_stock/tests/test_anglo_saxon_valuation_reconciliation.py b/addons/purchase_stock/tests/test_anglo_saxon_valuation_reconciliation.py index 69e51c811aa..05a43e4ee0a 100644 --- a/addons/purchase_stock/tests/test_anglo_saxon_valuation_reconciliation.py +++ b/addons/purchase_stock/tests/test_anglo_saxon_valuation_reconciliation.py @@ -106,11 +106,10 @@ class TestValuationReconciliation(ValuationReconciliationTestCommon): # Refund the invoice 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': 'modify', 'date': '2018-03-15', 'journal_id': invoice.journal_id.id, }) - new_invoice = self.env['account.move'].browse(refund_invoice_wiz.reverse_moves()['res_id']) + new_invoice = self.env['account.move'].browse(refund_invoice_wiz.modify_moves()['res_id']) refund_invoice = invoice.reversal_move_id # Check the result self.assertEqual(invoice.payment_state, 'reversed', "Invoice should be in 'reversed' state") diff --git a/addons/sale/tests/test_sale_refund.py b/addons/sale/tests/test_sale_refund.py index ccb0b6c2fc5..0410fde6323 100644 --- a/addons/sale/tests/test_sale_refund.py +++ b/addons/sale/tests/test_sale_refund.py @@ -92,11 +92,10 @@ class TestSaleRefund(TestSaleCommon): # Make a credit note 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() + credit_note_wizard.refund_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 # Check invoice's type and number @@ -153,67 +152,6 @@ class TestSaleRefund(TestSaleCommon): self.assertEqual(line.untaxed_amount_invoiced, 0.0, "Amount invoiced decreased as the refund is now confirmed") self.assertEqual(len(line.invoice_lines), 2, "The line 'ordered service' is invoiced, so it should be linked to 2 invoice lines (invoice and refund)") - def test_refund_cancel(self): - """ Test invoice with a refund in 'cancel' mode, meaning a refund will be created and auto confirm to completely cancel the first - customer invoice. The SO will have 2 invoice (customer + refund) in a paid state at the end. """ - # Increase quantity of an invoice lines - with Form(self.invoice) as invoice_form: - with invoice_form.invoice_line_ids.edit(0) as line_form: - line_form.quantity = 6 - with invoice_form.invoice_line_ids.edit(1) as line_form: - line_form.quantity = 4 - - # Validate invoice - self.invoice.action_post() - - # Check quantity to invoice on SO lines - for line in self.sale_order.order_line: - if line.product_id.invoice_policy == 'delivery': - self.assertEqual(line.qty_to_invoice, 0.0, "Quantity to invoice should be same as ordered quantity") - self.assertEqual(line.qty_invoiced, 0.0, "Invoiced quantity should be zero as no any invoice created for SO") - self.assertEqual(line.untaxed_amount_to_invoice, 0.0, "The amount to invoice should be zero, as the line based on delivered quantity") - self.assertEqual(line.untaxed_amount_invoiced, 0.0, "The invoiced amount should be zero, as the line based on delivered quantity") - self.assertFalse(line.invoice_lines, "The line based on delivered qty are not invoiced, so they should not be linked to invoice line") - else: - self.assertEqual(line.untaxed_amount_to_invoice, line.price_unit * line.qty_to_invoice, "Amount to invoice is now set as qty to invoice * unit price since no price change on invoice, for ordered products") - self.assertEqual(line.untaxed_amount_invoiced, line.price_unit * line.qty_invoiced, "Amount invoiced is now set as qty invoiced * unit price since no price change on invoice, for ordered products") - self.assertEqual(len(line.invoice_lines), 1, "The lines 'ordered' qty are invoiced, so it should be linked to 1 invoice lines") - - self.assertEqual(line.qty_invoiced, line.product_uom_qty + 1, "The quantity invoiced is +1 unit from the one of the sale line, as we modified invoice lines (%s)" % (line.name,)) - 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, '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']) - - # Check invoice's type and number - self.assertEqual(invoice_refund.move_type, 'out_refund', 'The last created invoiced should be a customer invoice') - self.assertEqual(invoice_refund.payment_state, 'paid', 'Last Customer creadit note should be in paid state') - self.assertEqual(self.sale_order.invoice_count, 2, "The SO should have 3 related invoices: the original, the refund, and the new one") - self.assertEqual(len(self.sale_order.invoice_ids.filtered(lambda inv: inv.move_type == 'out_refund')), 1, "The SO should be linked to only one refund") - self.assertEqual(len(self.sale_order.invoice_ids.filtered(lambda inv: inv.move_type == 'out_invoice')), 1, "The SO should be linked to only one customer invoices") - - # At this time, the invoice 1 is opened (validated) and its refund validated too, so the amounts invoiced are zero for - # all sale line. All invoiceable Sale lines have - for line in self.sale_order.order_line: - if line.product_id.invoice_policy == 'delivery': - self.assertEqual(line.qty_to_invoice, 0.0, "Quantity to invoice should be same as ordered quantity") - self.assertEqual(line.qty_invoiced, 0.0, "Invoiced quantity should be zero as no any invoice created for SO line based on delivered qty") - self.assertEqual(line.untaxed_amount_to_invoice, 0.0, "The amount to invoice should be zero, as the line based on delivered quantity") - self.assertEqual(line.untaxed_amount_invoiced, 0.0, "The invoiced amount should be zero, as the line based on delivered quantity") - self.assertFalse(line.invoice_lines, "The line based on delivered are not invoiced, so they should not be linked to invoice line") - else: - self.assertEqual(line.qty_to_invoice, line.product_uom_qty, "The quantity to invoice should be the ordered quantity") - self.assertEqual(line.qty_invoiced, 0, "The quantity invoiced is zero as the refund (paid) completely cancel the first invoice") - - self.assertEqual(line.untaxed_amount_to_invoice, line.price_unit * line.qty_to_invoice, "Amount to invoice is now set as qty to invoice * unit price since no price change on invoice, for ordered products") - self.assertEqual(line.untaxed_amount_invoiced, line.price_unit * line.qty_invoiced, "Amount invoiced is now set as qty invoiced * unit price since no price change on invoice, for ordered products") - self.assertEqual(len(line.invoice_lines), 2, "The lines 'ordered' qty are invoiced, so it should be linked to 1 invoice lines") - def test_refund_modify(self): """ Test invoice with a refund in 'modify' mode, and check customer invoices credit note is created from respective invoice """ # Decrease quantity of an invoice lines @@ -247,11 +185,10 @@ class TestSaleRefund(TestSaleCommon): # Make a credit note 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']) + invoice_refund = self.env['account.move'].browse(credit_note_wizard.modify_moves()['res_id']) # Check invoice's type and number self.assertEqual(invoice_refund.move_type, 'out_invoice', 'The last created invoiced should be a customer invoice') @@ -384,11 +321,10 @@ class TestSaleRefund(TestSaleCommon): so_invoice.action_post() credit_note_wizard = self.env['account.move.reversal'].with_context({'active_ids': [so_invoice.id], 'active_id': so_invoice.id, 'active_model': 'account.move'}).create({ - 'refund_method': 'refund', 'reason': 'reason test refund with downpayment', 'journal_id': so_invoice.journal_id.id, }) - credit_note_wizard.reverse_moves() + credit_note_wizard.refund_moves() invoice_refund = sale_order_refund.invoice_ids.sorted(key=lambda inv: inv.id, reverse=False)[-1] invoice_refund.action_post() diff --git a/addons/sale_mrp/tests/test_sale_mrp_anglo_saxon_valuation.py b/addons/sale_mrp/tests/test_sale_mrp_anglo_saxon_valuation.py index a2a9838d085..dde258af42c 100644 --- a/addons/sale_mrp/tests/test_sale_mrp_anglo_saxon_valuation.py +++ b/addons/sale_mrp/tests/test_sale_mrp_anglo_saxon_valuation.py @@ -302,10 +302,9 @@ class TestSaleMRPAngloSaxonValuation(ValuationReconciliationTestCommon): # Add a credit note for the returned kit ctx = {'active_model': 'account.move', 'active_ids': invoice.ids} refund_wizard = self.env['account.move.reversal'].with_context(ctx).create({ - 'refund_method': 'refund', 'journal_id': invoice.journal_id.id, }) - action = refund_wizard.reverse_moves() + action = refund_wizard.refund_moves() reverse_invoice = self.env['account.move'].browse(action['res_id']) with Form(reverse_invoice) as reverse_invoice_form: with reverse_invoice_form.invoice_line_ids.edit(0) as line: diff --git a/addons/sale_mrp/tests/test_sale_mrp_flow.py b/addons/sale_mrp/tests/test_sale_mrp_flow.py index ea88818af98..9e57a6a022f 100644 --- a/addons/sale_mrp/tests/test_sale_mrp_flow.py +++ b/addons/sale_mrp/tests/test_sale_mrp_flow.py @@ -2220,10 +2220,9 @@ class TestSaleMrpFlow(ValuationReconciliationTestCommon): invoice01.action_post() move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=invoice01.ids).create({ - 'refund_method': 'modify', 'journal_id': invoice01.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.modify_moves() invoice02 = self.env['account.move'].browse(reversal['res_id']) invoice02.action_post() diff --git a/addons/sale_stock/tests/test_anglo_saxon_valuation.py b/addons/sale_stock/tests/test_anglo_saxon_valuation.py index 4423c0881a9..1b8de31822b 100644 --- a/addons/sale_stock/tests/test_anglo_saxon_valuation.py +++ b/addons/sale_stock/tests/test_anglo_saxon_valuation.py @@ -1441,10 +1441,9 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon): # Add a credit note for the returned product ctx = {'active_model': 'account.move', 'active_ids': invoice.ids} refund_wizard = self.env['account.move.reversal'].with_context(ctx).create({ - 'refund_method': 'refund', 'journal_id': invoice.journal_id.id, }) - action = refund_wizard.reverse_moves() + action = refund_wizard.refund_moves() reverse_invoice = self.env['account.move'].browse(action['res_id']) with Form(reverse_invoice) as reverse_invoice_form: with reverse_invoice_form.invoice_line_ids.edit(0) as line: @@ -1672,10 +1671,9 @@ class TestAngloSaxonValuation(ValuationReconciliationTestCommon): invoice01.action_post() move_reversal = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=invoice01.ids).create({ - 'refund_method': 'modify', 'journal_id': invoice01.journal_id.id, }) - reversal = move_reversal.reverse_moves() + reversal = move_reversal.modify_moves() invoice02 = self.env['account.move'].browse(reversal['res_id']) invoice02.action_post() diff --git a/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py b/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py index 763253041a8..13eb570d8be 100644 --- a/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py +++ b/addons/sale_stock/tests/test_anglo_saxon_valuation_reconciliation.py @@ -116,10 +116,9 @@ class TestValuationReconciliation(TestValuationReconciliationCommon): return_pick._action_done() 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': 'modify', 'journal_id': invoice.journal_id.id, }) - new_invoice = self.env['account.move'].browse(refund_invoice_wiz.reverse_moves()['res_id']) + new_invoice = self.env['account.move'].browse(refund_invoice_wiz.modify_moves()['res_id']) self.assertEqual(invoice.payment_state, 'reversed', "Invoice should be in 'reversed' state.") self.assertEqual(invoice.reversal_move_id.payment_state, 'paid', "Refund should be in 'paid' state.") self.assertEqual(new_invoice.state, 'draft', "New invoice should be in 'draft' state.") diff --git a/addons/sale_stock/tests/test_sale_stock_report.py b/addons/sale_stock/tests/test_sale_stock_report.py index 3c8f86bf8a1..2d8d565d409 100644 --- a/addons/sale_stock/tests/test_sale_stock_report.py +++ b/addons/sale_stock/tests/test_sale_stock_report.py @@ -394,11 +394,11 @@ class TestSaleStockInvoices(TestSaleCommon): # Refund the invoice refund_wizard = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=invoice01.ids).create({ - 'refund_method': 'cancel', 'journal_id': invoice01.journal_id.id, }) - res = refund_wizard.reverse_moves() + res = refund_wizard.refund_moves() refund_invoice = self.env['account.move'].browse(res['res_id']) + refund_invoice.action_post() # recieve the returned product stock_return_picking_form = Form(self.env['stock.return.picking'].with_context(active_ids=picking.ids, active_id=picking.sorted().ids[0], active_model='stock.picking')) @@ -454,10 +454,9 @@ class TestSaleStockInvoices(TestSaleCommon): # Refund the invoice with full refund and new draft invoice refund_wizard = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=invoice01.ids).create({ - 'refund_method': 'modify', 'journal_id': invoice01.journal_id.id, }) - res = refund_wizard.reverse_moves() + res = refund_wizard.modify_moves() invoice02 = self.env['account.move'].browse(res['res_id']) invoice02.action_post() diff --git a/addons/sale_timesheet/tests/test_reinvoice.py b/addons/sale_timesheet/tests/test_reinvoice.py index d10df27b5fc..a405f7be2aa 100644 --- a/addons/sale_timesheet/tests/test_reinvoice.py +++ b/addons/sale_timesheet/tests/test_reinvoice.py @@ -350,10 +350,9 @@ class TestReInvoice(TestCommonSaleTimesheet): } refund_invoice_wiz = self.env['account.move.reversal'].with_context(wiz_context).create({ 'reason': 'please reverse :c', - 'refund_method': 'refund', 'date': today, }) - refund_invoice = self.env['account.move'].browse(refund_invoice_wiz.reverse_moves()['res_id']) + refund_invoice = self.env['account.move'].browse(refund_invoice_wiz.refund_moves()['res_id']) refund_invoice.action_post() # reversing with action_reverse and then action_post does not reset the invoice_status to 'to invoice' in tests diff --git a/addons/stock_account/tests/test_stockvaluationlayer.py b/addons/stock_account/tests/test_stockvaluationlayer.py index 986525c32ff..e3d3be0d894 100644 --- a/addons/stock_account/tests/test_stockvaluationlayer.py +++ b/addons/stock_account/tests/test_stockvaluationlayer.py @@ -1150,10 +1150,9 @@ class TestAngloSaxonAccounting(AccountTestInvoicingCommon, TestStockValuationCom self.assertEqual(self.product1.standard_price, 15) refund_wizard = self.env['account.move.reversal'].with_context(active_model="account.move", active_ids=invoice.ids).create({ - 'refund_method': 'refund', 'journal_id': invoice.journal_id.id, }) - action = refund_wizard.reverse_moves() + action = refund_wizard.refund_moves() reverse_invoice = self.env['account.move'].browse(action['res_id']) with Form(reverse_invoice) as reverse_invoice_form: with reverse_invoice_form.invoice_line_ids.edit(0) as line: