[FIX] account: prevent moves from stealing lines
The balance check doesn't work when a line is being moved from one move
to another because we never notified the move owning the lines at the
start that the lines are being modified.
To reproduce using a simple CSV to import:
```csv
"line_ids/id","line_ids/product_id"
"__export__.account_move_line_9_25fb2fbf","[FURN_7777] Office Chair"
```
To reproduce using a simple server action:
```python
self.env['account.move'].create({'line_ids': [(4, 9)]})
```
We now notify the original move also, triggering everything that needs
to be triggered: sync of dynamic lines and the check for the balance.
closes odoo/odoo#146906
X-original-commit: 41beb0d4fcc70bebe51ff2c872903486be25dae7
Signed-off-by: Quentin De Paoli <qdp@odoo.com>
Signed-off-by: William André (wan) <wan@odoo.com>
This commit is contained in:
@@ -2401,6 +2401,13 @@ class AccountMove(models.Model):
|
||||
del vals['invoice_line_ids']
|
||||
return vals
|
||||
|
||||
def _stolen_move(self, vals):
|
||||
for command in vals.get('line_ids', ()):
|
||||
if command[0] == Command.LINK:
|
||||
yield self.env['account.move.line'].browse(command[1]).move_id.id
|
||||
if command[0] == Command.SET:
|
||||
yield from self.env['account.move.line'].browse(command[2]).move_id.ids
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
if any('state' in vals and vals.get('state') == 'posted' for vals in vals_list):
|
||||
@@ -2408,8 +2415,11 @@ class AccountMove(models.Model):
|
||||
container = {'records': self}
|
||||
with self._check_balanced(container):
|
||||
with self._sync_dynamic_lines(container):
|
||||
moves = super().create([self._sanitize_vals(vals) for vals in vals_list])
|
||||
container['records'] = moves
|
||||
for vals in vals_list:
|
||||
self._sanitize_vals(vals)
|
||||
stolen_moves = self.browse(set(move for vals in vals_list for move in self._stolen_move(vals)))
|
||||
moves = super().create(vals_list)
|
||||
container['records'] = moves | stolen_moves
|
||||
for move, vals in zip(moves, vals_list):
|
||||
if 'tax_totals' in vals:
|
||||
move.tax_totals = vals['tax_totals']
|
||||
@@ -2452,7 +2462,8 @@ class AccountMove(models.Model):
|
||||
field = self._fields[fname]
|
||||
if field.compute and not field.readonly:
|
||||
to_protect.append(field)
|
||||
container = {'records': self}
|
||||
stolen_moves = self.browse(set(move for move in self._stolen_move(vals)))
|
||||
container = {'records': self | stolen_moves}
|
||||
with self.env.protecting(to_protect, self), self._check_balanced(container):
|
||||
with self._sync_dynamic_lines(container):
|
||||
res = super(AccountMove, self.with_context(
|
||||
|
||||
@@ -1130,3 +1130,33 @@ class TestAccountMove(AccountTestInvoicingCommon):
|
||||
[("account_id", "=", account.id)], ["balance:sum"], ["account_root_id"]
|
||||
)[0]["balance"]
|
||||
self.assertEqual(balance, 500)
|
||||
|
||||
def test_line_steal(self):
|
||||
honest_move = self.env['account.move'].create({
|
||||
'line_ids': [
|
||||
Command.create({
|
||||
'name': 'receivable',
|
||||
'account_id': self.company_data['default_account_receivable'].id,
|
||||
'balance': 500.0,
|
||||
}),
|
||||
Command.create({
|
||||
'name': 'tax',
|
||||
'account_id': self.company_data['default_account_tax_sale'].id,
|
||||
'balance': -500.0,
|
||||
}),
|
||||
]
|
||||
})
|
||||
honest_move.action_post()
|
||||
|
||||
with self.assertRaisesRegex(UserError, 'not balanced'), self.env.cr.savepoint():
|
||||
self.env['account.move'].create({'line_ids': [Command.set(honest_move.line_ids[0].ids)]})
|
||||
|
||||
with self.assertRaisesRegex(UserError, 'not balanced'), self.env.cr.savepoint():
|
||||
self.env['account.move'].create({'line_ids': [Command.link(honest_move.line_ids[0].id)]})
|
||||
|
||||
stealer_move = self.env['account.move'].create({})
|
||||
with self.assertRaisesRegex(UserError, 'not balanced'), self.env.cr.savepoint():
|
||||
stealer_move.write({'line_ids': [Command.set(honest_move.line_ids[0].ids)]})
|
||||
|
||||
with self.assertRaisesRegex(UserError, 'not balanced'), self.env.cr.savepoint():
|
||||
stealer_move.write({'line_ids': [Command.link(honest_move.line_ids[0].id)]})
|
||||
|
||||
Reference in New Issue
Block a user