Skip to content

Commit b4ae543

Browse files
committed
[IMP] base: batching of _compute_commercial_partner
Should correctly handle / fallback to regular code when processing non-stored partners. Perf difference according to cprofile on my machine: original python: ncalls tottime percall cumtime percall filename:lineno(function) 1 0.134 0.134 205.380 205.380 res_partner.py:277(_compute_commercial_partner) SQLized 1 0.118 0.118 67.239 67.239 res_partner.py:280(_compute_commercial_partner) most of the time leftover seems to be in modified_draft
1 parent 1fb20fe commit b4ae543

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

odoo/addons/base/models/res_partner.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,32 @@ def _compute_get_ids(self):
275275

276276
@api.depends('is_company', 'parent_id.commercial_partner_id')
277277
def _compute_commercial_partner(self):
278+
self.env.cr.execute("""
279+
WITH RECURSIVE cpid(id, parent_id, commercial_partner_id, final) AS (
280+
SELECT
281+
id, parent_id, id,
282+
(coalesce(is_company, false) OR parent_id IS NULL) as final
283+
FROM res_partner
284+
WHERE id = ANY(%s)
285+
UNION
286+
SELECT
287+
cpid.id, p.parent_id, p.id,
288+
(coalesce(is_company, false) OR p.parent_id IS NULL) as final
289+
FROM res_partner p
290+
JOIN cpid ON (cpid.parent_id = p.id)
291+
WHERE NOT cpid.final
292+
)
293+
SELECT cpid.id, cpid.commercial_partner_id
294+
FROM cpid
295+
WHERE final AND id = ANY(%s);
296+
""", [self.ids, self.ids])
297+
298+
d = dict(self.env.cr.fetchall())
278299
for partner in self:
279-
if partner.is_company or not partner.parent_id:
300+
fetched = d.get(partner.id)
301+
if fetched is not None:
302+
partner.commercial_partner_id = fetched
303+
elif partner.is_company or not partner.parent_id:
280304
partner.commercial_partner_id = partner
281305
else:
282306
partner.commercial_partner_id = partner.parent_id.commercial_partner_id

odoo/addons/base/tests/test_base.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,41 @@ def test_40_res_partner_address_get(self):
252252
self.assertEqual(leaf111.address_get([]),
253253
{'contact': branch11.id}, 'Invalid address resolution, branch11 should now be contact')
254254

255+
def test_commercial_partner_nullcompany(self):
256+
""" The commercial partner is the first/nearest ancestor-or-self which
257+
is a company or doesn't have a parent
258+
"""
259+
P = self.env['res.partner']
260+
p0 = P.create({'name': '0', 'email': '0'})
261+
self.assertEqual(p0.commercial_partner_id, p0, "partner without a parent is their own commercial partner")
262+
263+
p1 = P.create({'name': '1', 'email': '1', 'parent_id': p0.id})
264+
self.assertEqual(p1.commercial_partner_id, p0, "partner's parent is their commercial partner")
265+
p12 = P.create({'name': '12', 'email': '12', 'parent_id': p1.id})
266+
self.assertEqual(p12.commercial_partner_id, p0, "partner's GP is their commercial partner")
267+
268+
p2 = P.create({'name': '2', 'email': '2', 'parent_id': p0.id, 'is_company': True})
269+
self.assertEqual(p2.commercial_partner_id, p2, "partner flagged as company is their own commercial partner")
270+
p21 = P.create({'name': '21', 'email': '21', 'parent_id': p2.id})
271+
self.assertEqual(p21.commercial_partner_id, p2, "commercial partner is closest ancestor with themselves as commercial partner")
272+
273+
p3 = P.create({'name': '3', 'email': '3', 'is_company': True})
274+
self.assertEqual(p3.commercial_partner_id, p3, "being both parent-less and company should be the same as either")
275+
276+
notcompanies = p0 | p1 | p12 | p21
277+
self.env.cr.execute('update res_partner set is_company=null where id = any(%s)', [notcompanies.ids])
278+
for parent in notcompanies:
279+
p = P.create({
280+
'name': parent.name + '_sub',
281+
'email': parent.email + '_sub',
282+
'parent_id': parent.id,
283+
})
284+
self.assertEqual(
285+
p.commercial_partner_id,
286+
parent.commercial_partner_id,
287+
"check that is_company=null is properly handled when looking for ancestor"
288+
)
289+
255290
def test_50_res_partner_commercial_sync(self):
256291
res_partner = self.env['res.partner']
257292
p0 = res_partner.create({'name': 'Sigurd Sunknife',

0 commit comments

Comments
 (0)