Merge pull request #266 from Tecnativa/10-contract-optimize

[10.0][IMP] contract: Performance boost 🚀
This commit is contained in:
Pedro M. Baeza
2019-01-24 19:44:53 +01:00
committed by GitHub
2 changed files with 44 additions and 17 deletions

View File

@@ -16,6 +16,25 @@ Configuration
To view discount field set *Discount on lines* in user access rights. To view discount field set *Discount on lines* in user access rights.
You might find that generating all pending invoices at once takes too much
time and produces some performance problems, mostly in cases where you
generate a lot of invoices in little time (i.e. when invoicing thousands
of contracts yearly, and you get to January 1st of the next year). To avoid
this bottleneck, the trick is to **increase the cron frequence and decrease
the contracts batch size**. The counterpart is that some invoices could not
be generated in the exact day you expected. To configure that:
#. Go to *Settings > Activate the developer mode*.
#. Go to *Settings > Technical > Automation > Scheduled Actions >
Generate Recurring Invoices from Contracts > Edit > Information*.
#. Set a lower interval. For example, change *Interval Unit* to *Hours*.
#. Go to the *Technical Data* tab, and add a batch size in *Arguments*.
For example, it should look like ``(20,)``.
#. Save.
That's it! From now on, only 20 invoices per hour will be generated.
That should take only a few seconds each hour, and shouln't block other users.
Usage Usage
===== =====

View File

@@ -255,12 +255,16 @@ class AccountAnalyticAccount(models.Model):
@api.multi @api.multi
def _create_invoice(self): def _create_invoice(self):
self.ensure_one() self.ensure_one()
invoice_vals = self._prepare_invoice() # Re-read contract with correct company
invoice = self.env['account.invoice'].create(invoice_vals) _self = self.with_context(self.get_invoice_context())
invoice_vals = _self._prepare_invoice()
invoice = _self.env['account.invoice'].create(invoice_vals)
# Lines are read from an env where expensive values are precomputed
for line in self.recurring_invoice_line_ids: for line in self.recurring_invoice_line_ids:
invoice_line_vals = self._prepare_invoice_line(line, invoice.id) invoice_line_vals = _self._prepare_invoice_line(line, invoice.id)
self.env['account.invoice.line'].create(invoice_line_vals) _self.env['account.invoice.line'].create(invoice_line_vals)
invoice.compute_taxes() # Update next invoice date for current contract
_self.recurring_next_date = _self.env.context['next_date']
return invoice return invoice
@api.multi @api.multi
@@ -287,6 +291,7 @@ class AccountAnalyticAccount(models.Model):
relativedelta(days=1)) relativedelta(days=1))
date_to = date_start date_to = date_start
ctx.update({ ctx.update({
'mail_notrack': True,
'next_date': next_date, 'next_date': next_date,
'date_format': date_format, 'date_format': date_format,
'date_from': date_from, 'date_from': date_from,
@@ -317,18 +322,21 @@ class AccountAnalyticAccount(models.Model):
:return: invoices created :return: invoices created
""" """
invoices = self.env['account.invoice'] _self = self.with_context(prefetch_fields=False)
for contract in self: invoices = _self.env['account.invoice']
if limit and len(invoices) >= limit: # Precompute expensive computed fields in batch
break recurring_lines = _self.mapped("recurring_invoice_line_ids")
if not contract.check_dates_valid(): recurring_lines._fields["price_unit"].determine_value(recurring_lines)
continue # Create invoices
# Re-read contract with correct company with _self.env.norecompute():
ctx = contract.get_invoice_context() for contract in _self:
invoices |= contract.with_context(ctx)._create_invoice() if limit and len(invoices) >= limit:
contract.write({ break
'recurring_next_date': fields.Date.to_string(ctx['next_date']) if not contract.check_dates_valid():
}) continue
invoices |= contract._create_invoice()
invoices.compute_taxes()
_self.recompute()
return invoices return invoices
@api.model @api.model