Add reversal option when cancelling move

Closes #5180
This commit is contained in:
Cédric Krier
2023-01-27 01:06:15 +01:00
parent 84514c49de
commit cb59e11ad4
7 changed files with 106 additions and 20 deletions
+1
View File
@@ -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
+18 -6
View File
@@ -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):
@@ -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'
@@ -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::
@@ -4,4 +4,7 @@ this repository contains the full copyright notices and license terms. -->
<form>
<label name="description"/>
<field name="description" colspan="3"/>
<label name="reversal"/>
<field name="reversal"/>
</form>
+13 -13
View File
@@ -158,19 +158,19 @@ class Move(metaclass=PoolMeta):
MoveLine.set_analytic_state(lines)
MoveLine.save(lines)
def cancel(self, default=None):
'Reverse credit/debit of analytic lines'
pool = Pool()
AnalyticLine = pool.get('analytic_account.line')
cancel_move = super(Move, self).cancel(default)
analytic_lines = []
for line in cancel_move.lines:
for analytic_line in line.analytic_lines:
analytic_line.debit, analytic_line.credit = (
analytic_line.credit, analytic_line.debit)
analytic_lines.append(analytic_line)
AnalyticLine.save(analytic_lines)
return cancel_move
def _cancel_default(self, reversal=False):
default = super()._cancel_default(reversal=reversal)
if reversal:
default['lines.analytic_lines.debit'] = (
lambda data: data['credit'])
default['lines.analytic_lines.credit'] = (
lambda data: data['debit'])
else:
default['lines.analytic_lines.debit'] = (
lambda data: data['debit'] * -1)
default['lines.analytic_lines.credit'] = (
lambda data: data['credit'] * -1)
return default
class MoveLine(metaclass=PoolMeta):
@@ -16,6 +16,8 @@ Activate modules::
>>> config = activate_modules('analytic_account')
>>> Reconciliation = Model.get('account.move.reconciliation')
Create company::
>>> _ = create_company()
@@ -93,7 +95,7 @@ Create Move analytic accounts::
>>> analytic_account.debit
Decimal('0.00')
Cancel Move::
Cancel reversal move::
>>> cancel_move = Wizard('account.move.cancel', [move])
>>> cancel_move.form.description = 'Cancel'
@@ -112,6 +114,32 @@ Cancel Move::
>>> analytic_account.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')
>>> move.reload()
>>> line, = [l for l in move.lines if l.account == receivable]
>>> bool(line.reconciliation)
True
>>> cancel_move, = [l.move for l in line.reconciliation.lines
... if l.move != move]
>>> cancel_move.origin == move
True
>>> analytic_account.reload()
>>> analytic_account.credit
Decimal('0.00')
>>> analytic_account.debit
Decimal('0.00')
Create Move without analytic accounts::
>>> move = Move()