From cc4f8df99f59dd7abed935c5acf58331e952a1a0 Mon Sep 17 00:00:00 2001 From: Martin Trigaux Date: Mon, 27 Jun 2016 16:11:03 +0200 Subject: [PATCH] [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. --- addons/account/models/partner.py | 52 +++++++++++-------- .../tests/test_account_customer_invoice.py | 5 ++ 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/addons/account/models/partner.py b/addons/account/models/partner.py index d69dd37c119..aecc689ee6f 100644 --- a/addons/account/models/partner.py +++ b/addons/account/models/partner.py @@ -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): diff --git a/addons/account/tests/test_account_customer_invoice.py b/addons/account/tests/test_account_customer_invoice.py index 565057d733d..ad92a99a16a 100644 --- a/addons/account/tests/test_account_customer_invoice.py +++ b/addons/account/tests/test_account_customer_invoice.py @@ -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(