257 lines
12 KiB
Python
257 lines
12 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||
|
|
||
|
from unittest.mock import patch
|
||
|
|
||
|
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):
|
||
|
|
||
|
def setUp(self):
|
||
|
super(TestPartnerAssign, self).setUp()
|
||
|
|
||
|
self.customer_uk = self.env['res.partner'].create({
|
||
|
'name': 'Nigel',
|
||
|
'country_id': self.env.ref('base.uk').id,
|
||
|
'city': 'Birmingham',
|
||
|
'zip': 'B46 3AG',
|
||
|
'street': 'Cannon Hill Park',
|
||
|
})
|
||
|
self.lead_uk = self.env['crm.lead'].create({
|
||
|
'type': 'opportunity',
|
||
|
'name': 'Office Design and Architecture',
|
||
|
'partner_id': self.customer_uk.id
|
||
|
})
|
||
|
|
||
|
def geo_find(addr, **kw):
|
||
|
return {
|
||
|
'Wavre, Belgium': (50.7158956, 4.6128075),
|
||
|
'Cannon Hill Park, B46 3AG Birmingham, United Kingdom': (52.45216, -1.898578),
|
||
|
}.get(addr)
|
||
|
|
||
|
patcher = patch('odoo.addons.base_geolocalize.models.base_geocoder.GeoCoder.geo_find', wraps=geo_find)
|
||
|
self.startPatcher(patcher)
|
||
|
|
||
|
def test_opportunity_count(self):
|
||
|
self.customer_uk.write({
|
||
|
'is_company': True,
|
||
|
'child_ids': [
|
||
|
(0, 0, {'name': 'Uk Children 1',
|
||
|
}),
|
||
|
(0, 0, {'name': 'Uk Children 2',
|
||
|
}),
|
||
|
],
|
||
|
})
|
||
|
lead_uk_assigned = self.env['crm.lead'].create({
|
||
|
'name': 'Office Design and Architecture',
|
||
|
'partner_assigned_id': self.customer_uk.id,
|
||
|
'type': 'opportunity',
|
||
|
})
|
||
|
children_leads = self.env['crm.lead'].create([
|
||
|
{'name': 'Children 1 Lead 1',
|
||
|
'partner_id': self.customer_uk.child_ids[0].id,
|
||
|
'type': 'lead'},
|
||
|
{'name': 'Children 1 Lead 2',
|
||
|
'partner_id': self.customer_uk.child_ids[0].id,
|
||
|
'type': 'lead'},
|
||
|
{'name': 'Children 2 Lead 1',
|
||
|
'partner_id': self.customer_uk.child_ids[1].id,
|
||
|
'type': 'lead'},
|
||
|
{'name': 'Children 2 Lead 2',
|
||
|
'partner_id': self.customer_uk.child_ids[1].id,
|
||
|
'type': 'lead'},
|
||
|
])
|
||
|
children_leads_assigned = self.env['crm.lead'].create([
|
||
|
{'name': 'Children 1 Lead 1',
|
||
|
'partner_assigned_id': self.customer_uk.child_ids[0].id,
|
||
|
'type': 'lead'},
|
||
|
{'name': 'Children 1 Lead 2',
|
||
|
'partner_assigned_id': self.customer_uk.child_ids[0].id,
|
||
|
'type': 'lead'},
|
||
|
{'name': 'Children 2 Lead 1',
|
||
|
'partner_assigned_id': self.customer_uk.child_ids[1].id,
|
||
|
'type': 'lead'},
|
||
|
{'name': 'Children 2 Lead 2',
|
||
|
'partner_assigned_id': self.customer_uk.child_ids[1].id,
|
||
|
'type': 'lead'},
|
||
|
])
|
||
|
|
||
|
self.assertEqual(
|
||
|
repr(self.customer_uk.action_view_opportunity()['domain']),
|
||
|
repr([('id', 'in', sorted(self.lead_uk.ids + lead_uk_assigned.ids + children_leads.ids))]),
|
||
|
'Parent: own + children leads + assigned'
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
repr(self.customer_uk.child_ids[0].action_view_opportunity()['domain']),
|
||
|
repr([('id', 'in', sorted(children_leads[0:2].ids + children_leads_assigned[0:2].ids))]),
|
||
|
'Children: own leads + assigned'
|
||
|
)
|
||
|
self.assertEqual(
|
||
|
repr(self.customer_uk.child_ids[1].action_view_opportunity()['domain']),
|
||
|
repr([('id', 'in', sorted(children_leads[2:].ids + children_leads_assigned[2:].ids))]),
|
||
|
'Children: own leads + assigned'
|
||
|
)
|
||
|
|
||
|
def test_partner_assign(self):
|
||
|
""" Test the automatic assignation using geolocalisation """
|
||
|
partner_be = self.env['res.partner'].create({
|
||
|
"name": "Agrolait",
|
||
|
"is_company": True,
|
||
|
"city": "Wavre",
|
||
|
"zip": "1300",
|
||
|
"country_id": self.env.ref("base.be").id,
|
||
|
"street": "69 rue de Namur",
|
||
|
"partner_weight": 10,
|
||
|
})
|
||
|
partner_uk = self.env['res.partner'].create({
|
||
|
"name": "Think Big Systems",
|
||
|
"is_company": True,
|
||
|
"city": "London",
|
||
|
"country_id": self.env.ref("base.uk").id,
|
||
|
"street": "89 Lingfield Tower",
|
||
|
"partner_weight": 10,
|
||
|
})
|
||
|
|
||
|
lead = self.lead_uk
|
||
|
|
||
|
# In order to test find nearest Partner functionality and assign to opportunity,
|
||
|
# I Set Geo Lattitude and Longitude according to partner address.
|
||
|
# YTI Note: We should probably mock the call
|
||
|
partner_be.with_context(force_geo_localize=True).geo_localize()
|
||
|
|
||
|
# I check Geo Latitude and Longitude of partner after set
|
||
|
self.assertTrue(50 < partner_be.partner_latitude < 51, "Latitude is wrong: 50 < %s < 51" % partner_be.partner_latitude)
|
||
|
self.assertTrue(3 < partner_be.partner_longitude < 5, "Longitude is wrong: 3 < %s < 5" % partner_be.partner_longitude)
|
||
|
|
||
|
# I assign nearest partner to opportunity.
|
||
|
lead.assign_partner()
|
||
|
|
||
|
# I check assigned partner of opportunity who is nearest Geo Latitude and Longitude of opportunity.
|
||
|
self.assertEqual(lead.partner_assigned_id, partner_uk, "Opportuniy is not assigned nearest partner")
|
||
|
self.assertTrue(50 < lead.partner_latitude < 55, "Latitude is wrong: 50 < %s < 55" % lead.partner_latitude)
|
||
|
self.assertTrue(-4 < lead.partner_longitude < -1, "Longitude is wrong: -4 < %s < -1" % lead.partner_longitude)
|
||
|
self.assertTrue(lead.date_partner_assign, "Partner Assignment Date should be set")
|
||
|
|
||
|
# I forward this opportunity to its nearest partner.
|
||
|
context = dict(self.env.context, default_model='crm.lead', default_res_id=lead.id, active_ids=lead.ids)
|
||
|
lead_forwarded = self.env['crm.lead.forward.to.partner'].with_context(context).create({})
|
||
|
try:
|
||
|
lead_forwarded.action_forward()
|
||
|
except:
|
||
|
pass
|
||
|
|
||
|
|
||
|
class TestPartnerLeadPortal(TestCrmCommon):
|
||
|
|
||
|
def setUp(self):
|
||
|
super(TestPartnerLeadPortal, self).setUp()
|
||
|
# Partner Grade
|
||
|
self.grade = self.env['res.partner.grade'].create({
|
||
|
'name': "Grade Test",
|
||
|
'partner_weight': 42,
|
||
|
'sequence': 3,
|
||
|
})
|
||
|
# Integrating user/partner, having a salesman
|
||
|
self.user_portal = mail_new_test_user(
|
||
|
self.env, login='user_portal',
|
||
|
name='Patrick Portal', email='portal@test.example.com',
|
||
|
company_id=self.env.ref("base.main_company").id,
|
||
|
grade_id=self.grade.id,
|
||
|
user_id=self.user_sales_manager.id,
|
||
|
notification_type='email',
|
||
|
groups='base.group_portal',
|
||
|
)
|
||
|
|
||
|
# New lead, assigned to the new portal
|
||
|
self.lead_portal = self.env['crm.lead'].with_context(mail_notrack=True).create({
|
||
|
'type': "lead",
|
||
|
'name': "Test lead new",
|
||
|
'user_id': False,
|
||
|
'team_id': False,
|
||
|
'description': "This is the description of the test new lead.",
|
||
|
'partner_assigned_id': self.user_portal.partner_id.id
|
||
|
})
|
||
|
|
||
|
def test_partner_lead_accept(self):
|
||
|
""" Test an integrating partner accepting the lead """
|
||
|
self.lead_portal.with_user(self.user_portal).partner_interested(comment="Oh yeah, I take that lead !")
|
||
|
self.assertEqual(self.lead_portal.type, 'opportunity')
|
||
|
|
||
|
def test_partner_lead_decline(self):
|
||
|
""" Test an integrating partner decline the lead """
|
||
|
self.lead_portal.with_user(self.user_portal).partner_desinterested(comment="No thanks, I have enough leads !", contacted=True, spam=False)
|
||
|
|
||
|
self.assertFalse(self.lead_portal.partner_assigned_id.id, 'The partner_assigned_id of the declined lead should be False.')
|
||
|
self.assertTrue(self.user_portal.partner_id in self.lead_portal.sudo().partner_declined_ids, 'Partner who has declined the lead should be in the declined_partner_ids.')
|
||
|
|
||
|
def test_lead_access_right(self):
|
||
|
""" Test another portal user can not write on every leads """
|
||
|
# portal user having no right
|
||
|
poor_portal_user = self.env['res.users'].with_context({'no_reset_password': True, 'mail_notrack': True}).create({
|
||
|
'name': 'Poor Partner (not integrating one)',
|
||
|
'email': 'poor.partner@ododo.com',
|
||
|
'login': 'poorpartner',
|
||
|
'groups_id': [(6, 0, [self.env.ref('base.group_portal').id])],
|
||
|
})
|
||
|
# try to accept a lead that is not mine
|
||
|
with self.assertRaises(AccessError):
|
||
|
self.lead_portal.with_user(poor_portal_user).partner_interested(comment="Oh yeah, I take that lead !")
|
||
|
|
||
|
def test_lead_creation(self):
|
||
|
""" Test the opportinuty creation from portal """
|
||
|
data = self.env['crm.lead'].with_user(self.user_portal).create_opp_portal({
|
||
|
'title': "L'ours bleu",
|
||
|
'description': 'A good joke',
|
||
|
'contact_name': 'Renaud Rutten',
|
||
|
})
|
||
|
opportunity = self.env['crm.lead'].browse(data['id'])
|
||
|
salesmanteam = self.env['crm.team']._get_default_team_id(user_id=self.user_portal.user_id.id)
|
||
|
|
||
|
self.assertEqual(opportunity.team_id, salesmanteam, 'The created opportunity should have the same team as the salesman default team of the opportunity creator.')
|
||
|
self.assertEqual(opportunity.partner_assigned_id, self.user_portal.partner_id, 'Assigned Partner of created opportunity is the (portal) creator.')
|
||
|
|
||
|
def test_portal_mixin_url(self):
|
||
|
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")
|