From 7fa9ec263876d2fce2af78d5642559812cbb66b9 Mon Sep 17 00:00:00 2001 From: William Henrotin Date: Tue, 1 Dec 2020 15:35:41 +0000 Subject: [PATCH] [IMP] stock_account: create account moves in batch This commit groups creation and posting of account moves related to stock valuation in case of automatic valuation product. Previously, the account move were created one by one and posted right at the creation. Which can really slow (for instance running _run_fifo_vaccum with a large amount of remaining quantity layer) closes odoo/odoo#62700 Signed-off-by: Arnold Moyaux --- addons/stock_account/models/product.py | 11 ++-- addons/stock_account/models/stock_move.py | 55 ++++++++----------- .../stock_account/models/stock_move_line.py | 6 +- .../models/stock_valuation_layer.py | 16 ++++++ 4 files changed, 46 insertions(+), 42 deletions(-) diff --git a/addons/stock_account/models/product.py b/addons/stock_account/models/product.py index 8ff09ba1ee7..7a91a181693 100644 --- a/addons/stock_account/models/product.py +++ b/addons/stock_account/models/product.py @@ -362,6 +362,7 @@ class ProductProduct(models.Model): ('stock_move_id', '!=', False), ('company_id', '=', company.id), ], order='create_date, id') + as_svls = [] for svl_to_vacuum in svls_to_vacuum: domain = [ ('company_id', '=', svl_to_vacuum.company_id.id), @@ -431,13 +432,13 @@ class ProductProduct(models.Model): if product.cost_method == 'average' and not float_is_zero(product.quantity_svl, precision_rounding=self.uom_id.rounding): product.sudo().with_context(disable_auto_svl=True).write({'standard_price': product.value_svl / product.quantity_svl}) - # Create the account move. if self.valuation != 'real_time': continue - vacuum_svl.stock_move_id._account_entry_move( - vacuum_svl.quantity, vacuum_svl.description, vacuum_svl.id, vacuum_svl.value - ) - # Create the related expense entry + as_svls.append((vacuum_svl, svl_to_vacuum)) + + self.env['stock.valuation.layer'].browse(x[0].id for x in as_svls)._validate_accounting_entries() + + for vacuum_svl, svl_to_vacuum in as_svls: self._create_fifo_vacuum_anglo_saxon_expense_entry(vacuum_svl, svl_to_vacuum) def _create_fifo_vacuum_anglo_saxon_expense_entry(self, vacuum_svl, svl_to_vacuum): diff --git a/addons/stock_account/models/stock_move.py b/addons/stock_account/models/stock_move.py index 46cfc895e4a..aefe051f4a3 100644 --- a/addons/stock_account/models/stock_move.py +++ b/addons/stock_account/models/stock_move.py @@ -260,12 +260,7 @@ class StockMove(models.Model): stock_valuation_layers |= getattr(todo_valued_moves, '_create_%s_svl' % valued_type)() - for svl in stock_valuation_layers: - if not svl.product_id.valuation == 'real_time': - continue - if svl.currency_id.is_zero(svl.value): - continue - svl.stock_move_id._account_entry_move(svl.quantity, svl.description, svl.id, svl.value) + stock_valuation_layers._validate_accounting_entries() stock_valuation_layers._check_company() @@ -437,23 +432,20 @@ class StockMove(models.Model): vals['to_refund'] = self.to_refund return vals - def _create_account_move_line(self, credit_account_id, debit_account_id, journal_id, qty, description, svl_id, cost): + def _prepare_account_move_vals(self, credit_account_id, debit_account_id, journal_id, qty, description, svl_id, cost): self.ensure_one() - AccountMove = self.env['account.move'].with_context(default_journal_id=journal_id) move_lines = self._prepare_account_move_line(qty, cost, credit_account_id, debit_account_id, description) - if move_lines: - date = self._context.get('force_period_date', fields.Date.context_today(self)) - new_account_move = AccountMove.sudo().create({ - 'journal_id': journal_id, - 'line_ids': move_lines, - 'date': date, - 'ref': description, - 'stock_move_id': self.id, - 'stock_valuation_layer_ids': [(6, None, [svl_id])], - 'move_type': 'entry', - }) - new_account_move._post() + date = self._context.get('force_period_date', fields.Date.context_today(self)) + return { + 'journal_id': journal_id, + 'line_ids': move_lines, + 'date': date, + 'ref': description, + 'stock_move_id': self.id, + 'stock_valuation_layer_ids': [(6, None, [svl_id])], + 'move_type': 'entry', + } def _account_entry_move(self, qty, description, svl_id, cost): """ Accounting Valuation Entries """ @@ -465,46 +457,43 @@ class StockMove(models.Model): # if the move isn't owned by the company, we don't make any valuation return False - location_from = self.location_id - location_to = self.location_dest_id company_from = self._is_out() and self.mapped('move_line_ids.location_id.company_id') or False company_to = self._is_in() and self.mapped('move_line_ids.location_dest_id.company_id') or False journal_id, acc_src, acc_dest, acc_valuation = self._get_accounting_data_for_valuation() # Create Journal Entry for products arriving in the company; in case of routes making the link between several # warehouse of the same company, the transit location belongs to this company, so we don't need to create accounting entries + am_vals = [] if self._is_in(): if self._is_returned(valued_type='in'): - self.with_company(company_to)._create_account_move_line(acc_dest, acc_valuation, journal_id, qty, description, svl_id, cost) + am_vals.append(self.with_company(company_to)._prepare_account_move_vals(acc_dest, acc_valuation, journal_id, qty, description, svl_id, cost)) else: - self.with_company(company_to)._create_account_move_line(acc_src, acc_valuation, journal_id, qty, description, svl_id, cost) + am_vals.append(self.with_company(company_to)._prepare_account_move_vals(acc_src, acc_valuation, journal_id, qty, description, svl_id, cost)) # Create Journal Entry for products leaving the company if self._is_out(): cost = -1 * cost if self._is_returned(valued_type='out'): - self.with_company(company_from)._create_account_move_line(acc_valuation, acc_src, journal_id, qty, description, svl_id, cost) + am_vals.append(self.with_company(company_from)._prepare_account_move_vals(acc_valuation, acc_src, journal_id, qty, description, svl_id, cost)) else: - self.with_company(company_from)._create_account_move_line(acc_valuation, acc_dest, journal_id, qty, description, svl_id, cost) + am_vals.append(self.with_company(company_from)._prepare_account_move_vals(acc_valuation, acc_dest, journal_id, qty, description, svl_id, cost)) if self.company_id.anglo_saxon_accounting: # Creates an account entry from stock_input to stock_output on a dropship move. https://github.com/odoo/odoo/issues/12687 if self._is_dropshipped(): if cost > 0: - self.with_company(self.company_id)._create_account_move_line(acc_src, acc_valuation, journal_id, qty, description, svl_id, cost) + am_vals.append(self.with_company(self.company_id)._prepare_account_move_vals(acc_src, acc_valuation, journal_id, qty, description, svl_id, cost)) else: cost = -1 * cost - self.with_company(self.company_id)._create_account_move_line(acc_valuation, acc_dest, journal_id, qty, description, svl_id, cost) + am_vals.append(self.with_company(self.company_id)._prepare_account_move_vals(acc_valuation, acc_dest, journal_id, qty, description, svl_id, cost)) elif self._is_dropshipped_returned(): if cost > 0: - self.with_company(self.company_id)._create_account_move_line(acc_valuation, acc_src, journal_id, qty, description, svl_id, cost) + am_vals.append(self.with_company(self.company_id)._prepare_account_move_vals(acc_valuation, acc_src, journal_id, qty, description, svl_id, cost)) else: cost = -1 * cost - self.with_company(self.company_id)._create_account_move_line(acc_dest, acc_valuation, journal_id, qty, description, svl_id, cost) + am_vals.append(self.with_company(self.company_id)._prepare_account_move_vals(acc_dest, acc_valuation, journal_id, qty, description, svl_id, cost)) - if self.company_id.anglo_saxon_accounting: - # Eventually reconcile together the invoice and valuation accounting entries on the stock interim accounts - self._get_related_invoices()._stock_account_anglo_saxon_reconcile_valuation(product=self.product_id) + return am_vals def _get_related_invoices(self): # To be overridden in purchase and sale_stock """ This method is overrided in both purchase and sale_stock modules to adapt diff --git a/addons/stock_account/models/stock_move_line.py b/addons/stock_account/models/stock_move_line.py index 4187f20113e..e0b3fd712a6 100644 --- a/addons/stock_account/models/stock_move_line.py +++ b/addons/stock_account/models/stock_move_line.py @@ -56,7 +56,5 @@ class StockMoveLine(models.Model): elif move._is_dropshipped() and diff < 0 or move._is_dropshipped_returned() and diff > 0: stock_valuation_layers |= move._create_dropshipped_returned_svl(forced_quantity=abs(diff)) - for svl in stock_valuation_layers: - if not svl.product_id.valuation == 'real_time': - continue - svl.stock_move_id._account_entry_move(svl.quantity, svl.description, svl.id, svl.value) + stock_valuation_layers._validate_accounting_entries() + diff --git a/addons/stock_account/models/stock_valuation_layer.py b/addons/stock_account/models/stock_valuation_layer.py index ffb96e4b773..a840dc29032 100644 --- a/addons/stock_account/models/stock_valuation_layer.py +++ b/addons/stock_account/models/stock_valuation_layer.py @@ -36,3 +36,19 @@ class StockValuationLayer(models.Model): self._table, ['product_id', 'remaining_qty', 'stock_move_id', 'company_id', 'create_date'] ) + def _validate_accounting_entries(self): + am_vals = [] + for svl in self: + if not svl.product_id.valuation == 'real_time': + continue + if svl.currency_id.is_zero(svl.value): + continue + am_vals += svl.stock_move_id._account_entry_move(svl.quantity, svl.description, svl.id, svl.value) + if am_vals: + account_moves = self.env['account.move'].sudo().create(am_vals) + account_moves._post() + if self.company_id.anglo_saxon_accounting: + # Eventually reconcile together the invoice and valuation accounting entries on the stock interim accounts + for svl in self: + svl.stock_move_id._get_related_invoices()._stock_account_anglo_saxon_reconcile_valuation(product=svl.product_id) +