[FIX] account: compute total invoice in batch

The computation of the total_invoiced field did not work in batch mode.
When displaying a company in a form view (field invoice_total comptued), the
children of this company are present in the cache and the value of the field
invoice_total will be prefetched for these children as well (at least in 9.0).
Most of the time this is redudant information and the same value is computed
for each child while most of the invoices are on the parent.

Batching the computation per partner allows to make one global query for all
partners.

Add test to make sure the total increase correctly after a test invoice
confirmation.
This commit is contained in:
Martin Trigaux
2016-06-27 17:20:05 +02:00
parent 9062c01c02
commit cc4f8df99f
2 changed files with 34 additions and 23 deletions
+29 -23
View File
@@ -290,31 +290,37 @@ class ResPartner(models.Model):
return True
user_currency_id = self.env.user.company_id.currency_id.id
all_partners_and_children = {}
all_partner_ids = []
for partner in self:
all_partner_ids = self.search([('id', 'child_of', partner.id)]).ids
# searching account.invoice.report via the orm is comparatively expensive
# (generates queries "id in []" forcing to build the full table).
# In simple cases where all invoices are in the same currency than the user's company
# access directly these elements
# generate where clause to include multicompany rules
where_query = account_invoice_report._where_calc([
('partner_id', 'in', all_partner_ids), ('state', 'not in', ['draft', 'cancel']), ('company_id', '=', self.env.user.company_id.id),
('type', 'in', ('out_invoice', 'out_refund'))
])
account_invoice_report._apply_ir_rules(where_query, 'read')
from_clause, where_clause, where_clause_params = where_query.get_sql()
query = """
SELECT SUM(price_total) as total
FROM account_invoice_report account_invoice_report
WHERE %s
""" % where_clause
# price_total is in the company currency
self.env.cr.execute(query, where_clause_params)
partner.total_invoiced = self.env.cr.fetchone()[0]
all_partners_and_children[partner] = self.search([('id', 'child_of', partner.id)]).ids
all_partner_ids += all_partners_and_children[partner]
# searching account.invoice.report via the orm is comparatively expensive
# (generates queries "id in []" forcing to build the full table).
# In simple cases where all invoices are in the same currency than the user's company
# access directly these elements
# generate where clause to include multicompany rules
where_query = account_invoice_report._where_calc([
('partner_id', 'in', all_partner_ids), ('state', 'not in', ['draft', 'cancel']), ('company_id', '=', self.env.user.company_id.id),
('type', 'in', ('out_invoice', 'out_refund'))
])
account_invoice_report._apply_ir_rules(where_query, 'read')
from_clause, where_clause, where_clause_params = where_query.get_sql()
# price_total is in the company currency
query = """
SELECT SUM(price_total) as total, partner_id
FROM account_invoice_report account_invoice_report
WHERE %s
GROUP BY partner_id
""" % where_clause
self.env.cr.execute(query, where_clause_params)
price_totals = self.env.cr.dictfetchall()
for partner, child_ids in all_partners_and_children.items():
partner.total_invoiced = sum(price['total'] for price in price_totals if price['partner_id'] in child_ids)
@api.multi
def _journal_item_count(self):
@@ -65,6 +65,8 @@ class TestAccountCustomerInvoice(AccountTestUsers):
tax = self.env['account.invoice.tax'].create(invoice_tax_line)
assert tax, "Tax has not been assigned correctly"
total_before_confirm = self.partner3.total_invoiced
# I check that Initially customer invoice is in the "Draft" state
self.assertEquals(self.account_invoice_customer0.state, 'draft')
@@ -92,6 +94,9 @@ class TestAccountCustomerInvoice(AccountTestUsers):
# I verify that invoice is now in Paid state
assert (self.account_invoice_customer0.state == 'paid'), "Invoice is not in Paid state"
total_after_confirm = self.partner3.total_invoiced
self.assertEquals(total_after_confirm - total_before_confirm, self.account_invoice_customer0.amount_untaxed_signed)
# I refund the invoice Using Refund Button
invoice_refund_obj = self.env['account.invoice.refund']
self.account_invoice_refund_0 = invoice_refund_obj.create(dict(