From cb59e11ad46a9b816e0d73bef3f61d88d776c4f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Fri, 27 Jan 2023 01:06:15 +0100 Subject: [PATCH] Add reversal option when cancelling move Closes #5180 --- modules/account/CHANGELOG | 1 + modules/account/move.py | 24 ++++++++--- .../account/tests/scenario_move_cancel.rst | 41 +++++++++++++++++++ modules/account/tests/scenario_tax_code.rst | 1 + .../account/view/move_cancel_default_form.xml | 3 ++ modules/analytic_account/line.py | 26 ++++++------ .../tests/scenario_analytic_account.rst | 30 +++++++++++++- 7 files changed, 106 insertions(+), 20 deletions(-) diff --git a/modules/account/CHANGELOG b/modules/account/CHANGELOG index 82b7ecd87f..9eec4a5785 100644 --- a/modules/account/CHANGELOG +++ b/modules/account/CHANGELOG @@ -1,3 +1,4 @@ +* Add reversal option when cancelling move * Add cumulative balance to payable/receivable lines * Rename reconciliation name to number * Accrue and allocate rounding errors when there are multiple taxes diff --git a/modules/account/move.py b/modules/account/move.py index a541516d04..21a19f89aa 100644 --- a/modules/account/move.py +++ b/modules/account/move.py @@ -369,7 +369,7 @@ class Move(ModelSQL, ModelView): cache_cls = cache[MoveLine.__name__] cache_cls.clear() - def _cancel_default(self): + def _cancel_default(self, reversal=False): 'Return default dictionary to cancel move' pool = Pool() Date = pool.get('ir.date') @@ -392,8 +392,12 @@ class Move(ModelSQL, ModelView): 'date': date, 'period': period_id, }) - default['lines.debit'] = lambda data: data['debit'] * -1 - default['lines.credit'] = lambda data: data['credit'] * -1 + if reversal: + default['lines.debit'] = lambda data: data['credit'] + default['lines.credit'] = lambda data: data['debit'] + else: + default['lines.debit'] = lambda data: data['debit'] * -1 + default['lines.credit'] = lambda data: data['credit'] * -1 default['lines.amount_second_currency'] = ( lambda data: data['amount_second_currency'] * -1 if data['amount_second_currency'] @@ -403,13 +407,13 @@ class Move(ModelSQL, ModelView): lambda data: 'account.move.line,%s' % data['id']) return default - def cancel(self, default=None): + def cancel(self, default=None, reversal=False): 'Return a cancel move' if default is None: default = {} else: default = default.copy() - default.update(self._cancel_default()) + default.update(self._cancel_default(reversal=reversal)) cancel_move, = self.copy([self], default=default) return cancel_move @@ -2215,7 +2219,8 @@ class CancelMoves(Wizard): with Transaction().set_user(0): Unreconcile.make_unreconciliation(moves_w_delegation[move]) default = self.default_cancel(move) - cancel_move = move.cancel(default=default) + cancel_move = move.cancel( + default=default, reversal=self.default.reversal) to_reconcile = defaultdict(list) for line in move.lines + cancel_move.lines: if line.account.reconcile: @@ -2229,6 +2234,13 @@ class CancelMovesDefault(ModelView): 'Cancel Moves' __name__ = 'account.move.cancel.default' description = fields.Char('Description') + reversal = fields.Boolean( + "Reversal", + help="Reverse debit and credit.") + + @classmethod + def default_reversal(cls): + return True class GroupLines(Wizard): diff --git a/modules/account/tests/scenario_move_cancel.rst b/modules/account/tests/scenario_move_cancel.rst index 4903a8f189..8df55a49f9 100644 --- a/modules/account/tests/scenario_move_cancel.rst +++ b/modules/account/tests/scenario_move_cancel.rst @@ -17,6 +17,8 @@ Activate modules:: >>> config = activate_modules('account') + >>> Reconciliation = Model.get('account.move.reconciliation') + Create company:: >>> _ = create_company() @@ -78,10 +80,49 @@ Create Move to cancel:: >>> receivable.debit Decimal('42.00') +Cancel reversal Move:: + + >>> cancel_move = Wizard('account.move.cancel', [move]) + >>> cancel_move.form.description = "Reversal" + >>> cancel_move.form.reversal = True + >>> cancel_move.execute('cancel') + >>> cancel_move.state + 'end' + >>> move.reload() + >>> [bool(l.reconciliation) for l in move.lines if l.account == receivable] + [True, True] + >>> line, _ = [l for l in move.lines if l.account == receivable] + >>> cancel_move, = [l.move for l in line.reconciliation.lines + ... if l.move != move] + >>> cancel_move.origin == move + True + >>> cancel_move.description + 'Reversal' + >>> sorted([l.origin.id for l in cancel_move.lines]) == \ + ... sorted(map(int, move.lines)) + True + >>> revenue.reload() + >>> revenue.credit + Decimal('42.00') + >>> revenue.debit + Decimal('42.00') + >>> receivable.reload() + >>> receivable.credit + Decimal('42.00') + >>> receivable.debit + Decimal('42.00') + + >>> reconciliations = { + ... l.reconciliation for l in cancel_move.lines if l.reconciliation} + >>> Reconciliation.delete(list(reconciliations)) + >>> cancel_move.reload() + >>> cancel_move.delete() + Cancel Move:: >>> cancel_move = Wizard('account.move.cancel', [move]) >>> cancel_move.form.description = 'Cancel' + >>> cancel_move.form.reversal = False >>> cancel_move.execute('cancel') >>> cancel_move.state 'end' diff --git a/modules/account/tests/scenario_tax_code.rst b/modules/account/tests/scenario_tax_code.rst index d9ef6f0808..8291ec5285 100644 --- a/modules/account/tests/scenario_tax_code.rst +++ b/modules/account/tests/scenario_tax_code.rst @@ -79,6 +79,7 @@ Create some moves:: >>> _ = move.duplicate() >>> cancel_move = Wizard('account.move.cancel', [move]) + >>> cancel_move.form.reversal = False >>> cancel_move.execute('cancel') Check tax code:: diff --git a/modules/account/view/move_cancel_default_form.xml b/modules/account/view/move_cancel_default_form.xml index 76c83d0ffd..c6a903e661 100644 --- a/modules/account/view/move_cancel_default_form.xml +++ b/modules/account/view/move_cancel_default_form.xml @@ -4,4 +4,7 @@ this repository contains the full copyright notices and license terms. -->