From 7ad5f2efbff0bffe3b86ac568aa183dd29850c40 Mon Sep 17 00:00:00 2001 From: "Andrzej(pian)" Date: Wed, 3 Jan 2024 10:44:19 +0100 Subject: [PATCH] [FIX] website_crm_partner_assign: reseller localization Issue Description: The partner() function previously inferred the country using GeoIP when no specific country (nor "all_countries") was specified. However, if there were no partners from the inferred country, the render function would lead to a broken screen. Resolution: Implemented a fallback mechanism to treat the situation as if no country was specified. This ensures that all partners are displayed in such cases, preventing the occurrence of a broken screen. [Reproducing bug] - odoo 16.4 with: website, contacts, crm_enterprise_partner_assign - Simulate GeoIP on the backend, so it points to some COUNTRY_A: - this can be achived by adding `country= country_obj.search([('name', 'ilike', 'mex')])` [below this line](https://github.com/odoo/odoo/blob/57d43aca2b07d3469a937890b7d5e5c4f29fe250/addons/website_crm_partner_assign/controllers/main.py#L237) - note: it doesn't matter which country you set it to, AS LONG AS COUNTRY_A != COUNTRY_B - in CRM/Contacts: - create partner (set Partner Level and country to COUNTRY_B of the record ) - Publish partner by "Go to website" -> Published - go to url: ODOO_WEBSITE/partners - BUG: No Partners are displayed opw-3598110 closes odoo/odoo#148822 X-original-commit: cfca987efe83e6a6ba27779246a2d5da6b86dc7f Signed-off-by: Nicolas Lempereur (nle) Signed-off-by: Andrzej Pietrusiak (pian) --- .../controllers/main.py | 26 +++++++++----- .../tests/test_partner_assign.py | 36 +++++++++++++++++++ 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/addons/website_crm_partner_assign/controllers/main.py b/addons/website_crm_partner_assign/controllers/main.py index 069b3594ac0..080eb19561e 100644 --- a/addons/website_crm_partner_assign/controllers/main.py +++ b/addons/website_crm_partner_assign/controllers/main.py @@ -230,11 +230,26 @@ class WebsiteCrmPartnerAssign(WebsitePartnerPage): if search: base_partner_domain += ['|', ('name', 'ilike', search), ('website_description', 'ilike', search)] - # group by grade - grade_domain = list(base_partner_domain) + # Infer Country if not country and not country_all: if request.geoip.country_code: country = country_obj.search([('code', '=', request.geoip.country_code)], limit=1) + + # Group by country + country_domain = list(base_partner_domain) + if grade: + country_domain += [('grade_id', '=', grade.id)] + countries = partner_obj.sudo().read_group( + country_domain, ["id", "country_id"], + groupby="country_id", orderby="country_id") + + # Fallback: Show all partners when country has no associates. + country_ids = [c['country_id'][0] for c in countries] + if country and country.id not in country_ids: + country = None + + # Group by grade + grade_domain = list(base_partner_domain) if country: grade_domain += [('country_id', '=', country.id)] grades = partner_obj.sudo().read_group( @@ -250,13 +265,6 @@ class WebsiteCrmPartnerAssign(WebsitePartnerPage): 'active': bool(grade is None), }) - # group by country - country_domain = list(base_partner_domain) - if grade: - country_domain += [('grade_id', '=', grade.id)] - countries = partner_obj.sudo().read_group( - country_domain, ["id", "country_id"], - groupby="country_id", orderby="country_id") countries_partners = partner_obj.sudo().search_count(country_domain) # flag active country for country_dict in countries: diff --git a/addons/website_crm_partner_assign/tests/test_partner_assign.py b/addons/website_crm_partner_assign/tests/test_partner_assign.py index 2dc127d5952..feb12fd96e7 100644 --- a/addons/website_crm_partner_assign/tests/test_partner_assign.py +++ b/addons/website_crm_partner_assign/tests/test_partner_assign.py @@ -7,6 +7,8 @@ from odoo.exceptions import AccessError from odoo.tests.common import TransactionCase from odoo.addons.crm.tests.common import TestCrmCommon from odoo.addons.mail.tests.common import mail_new_test_user +from odoo.addons.website.tools import MockRequest +from odoo.addons.website_crm_partner_assign.controllers.main import WebsiteCrmPartnerAssign class TestPartnerAssign(TransactionCase): @@ -218,3 +220,37 @@ class TestPartnerLeadPortal(TestCrmCommon): record_action = self.lead_portal._get_access_action(access_uid=self.user_portal.id) self.assertEqual(record_action['url'], '/my/opportunity/%s' % self.lead_portal.id) self.assertEqual(record_action['type'], 'ir.actions.act_url') + + @patch('odoo.http.GeoIP') + def test_03_crm_partner_assign_geolocalization(self, GeoIpMock): + """ + This test checks situation when "{OdooURL}/partners" is visited from foreign country without resellers. + It uses Mexico as an example. + + Why patching of GeoIP is used? + Tested function (WebsiteCrmPartnerAssign.partners) uses GeoIp.country_code which is read_only, because + of the property decorator https://docs.python.org/3/library/functions.html#property + Patching is allowing to modify normally read_only value. + """ + # Patch GeoIp so it acts, as if Odoo client is located in Mexico + GeoIpMock.return_value.country_code = 'MX' + + # Create a partner outside of Mexico + non_mexican_partner = self.env['res.partner'].create({ + 'name': 'Non_Mexican_Partner', + 'is_company': True, + 'grade_id': self.env['res.partner.grade'].search([], limit=1).id, + 'website_published': True, + 'country_id': self.env['res.country'].search([('code', '!=', 'mx')], limit=1).id + }) + + def render_function(_, values, *args, **kwargs): + """ Tests values at the end of WebsiteCrmPartnerAssign.partners method.""" + self.assertIn("partners", values, "Partner key is not present in the values, can't perform subsequent checks.") + self.assertIn(non_mexican_partner, values['partners'], "Non-Mexican Partner is not present when rendering partners from Mexico; fallback protection (protecting from no results) didn't work.") + return 'rendered' + + with MockRequest(self.env, website=self.env['website'].browse(1)) as mock_request: + mock_request.render = render_function + res = WebsiteCrmPartnerAssign().partners() + self.assertEqual([b'rendered'], res.response, "render_function wasn't called")