diff --git a/addons/crm/__manifest__.py b/addons/crm/__manifest__.py index 8c7a6a892f5..839a1e70ef3 100644 --- a/addons/crm/__manifest__.py +++ b/addons/crm/__manifest__.py @@ -26,33 +26,35 @@ 'security/crm_security.xml', 'security/ir.model.access.csv', - 'data/crm_data.xml', - 'data/crm_stage_data.xml', - 'data/crm_lead_data.xml', - 'data/digest_data.xml', 'data/crm_lead_prediction_data.xml', + 'data/crm_lost_reason_data.xml', + 'data/crm_stage_data.xml', + 'data/crm_team_data.xml', + 'data/digest_data.xml', + 'data/mail_data.xml', 'wizard/crm_lead_lost_views.xml', 'wizard/crm_lead_to_opportunity_views.xml', 'wizard/crm_lead_to_opportunity_mass_views.xml', 'wizard/crm_merge_opportunities_views.xml', - 'views/crm_templates.xml', - 'views/res_config_settings_views.xml', - 'views/crm_views.xml', + 'views/assets.xml', + 'views/calendar_views.xml', + 'views/crm_menu_views.xml', 'views/crm_lost_reason_views.xml', 'views/crm_stage_views.xml', 'views/crm_lead_views.xml', - 'views/calendar_views.xml', + 'views/digest_views.xml', + 'views/mail_activity_views.xml', + 'views/res_config_settings_views.xml', 'views/res_partner_views.xml', + 'views/utm_campaign_views.xml', 'report/crm_activity_report_views.xml', 'report/crm_opportunity_report_views.xml', 'views/crm_team_views.xml', - 'views/digest_views.xml', - 'views/utm_campaign_views.xml' ], 'demo': [ - 'data/crm_demo.xml', + 'data/crm_team_demo.xml', 'data/mail_activity_demo.xml', 'data/crm_lead_demo.xml', ], diff --git a/addons/crm/data/crm_data.xml b/addons/crm/data/crm_data.xml deleted file mode 100644 index 0ee888fea90..00000000000 --- a/addons/crm/data/crm_data.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - Too expensive - - - We don't have people/skills - - - Not enough stock - - - diff --git a/addons/crm/data/crm_lost_reason_data.xml b/addons/crm/data/crm_lost_reason_data.xml new file mode 100644 index 00000000000..a13a1d77b34 --- /dev/null +++ b/addons/crm/data/crm_lost_reason_data.xml @@ -0,0 +1,13 @@ + + + + + Too expensive + + + We don't have people/skills + + + Not enough stock + + diff --git a/addons/crm/data/crm_team_data.xml b/addons/crm/data/crm_team_data.xml new file mode 100644 index 00000000000..016777ce78f --- /dev/null +++ b/addons/crm/data/crm_team_data.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/addons/crm/data/crm_demo.xml b/addons/crm/data/crm_team_demo.xml similarity index 67% rename from addons/crm/data/crm_demo.xml rename to addons/crm/data/crm_team_demo.xml index f5f0ed06bed..f04c60baa30 100644 --- a/addons/crm/data/crm_demo.xml +++ b/addons/crm/data/crm_team_demo.xml @@ -1,14 +1,9 @@ - - - - sales - diff --git a/addons/crm/data/crm_lead_data.xml b/addons/crm/data/mail_data.xml similarity index 92% rename from addons/crm/data/crm_lead_data.xml rename to addons/crm/data/mail_data.xml index 52f7575aa79..28253e529b5 100644 --- a/addons/crm/data/crm_lead_data.xml +++ b/addons/crm/data/mail_data.xml @@ -1,6 +1,13 @@ + + + + + + + diff --git a/addons/crm/models/crm_team.py b/addons/crm/models/crm_team.py index 25b1965de97..9161c69116c 100644 --- a/addons/crm/models/crm_team.py +++ b/addons/crm/models/crm_team.py @@ -15,7 +15,9 @@ class Team(models.Model): use_leads = fields.Boolean('Leads', help="Check this box to filter and qualify incoming requests as leads before converting them into opportunities and assigning them to a salesperson.") use_opportunities = fields.Boolean('Pipeline', default=True, help="Check this box to manage a presales process with opportunities.") - alias_id = fields.Many2one('mail.alias', string='Alias', ondelete="restrict", required=True, help="The email address associated with this channel. New emails received will automatically create new leads assigned to the channel.") + alias_id = fields.Many2one( + 'mail.alias', string='Alias', ondelete="restrict", required=True, + help="The email address associated with this channel. New emails received will automatically create new leads assigned to the channel.") # statistics about leads / opportunities / both lead_unassigned_count = fields.Integer( string='# Unassigned Leads', compute='_compute_lead_unassigned_count') @@ -118,6 +120,7 @@ class Team(models.Model): if not use_leads and not use_opportunities: return {'alias_name': False} return {} + # ------------------------------------------------------------ # MESSAGING # ------------------------------------------------------------ @@ -162,7 +165,7 @@ class Team(models.Model): return action def _compute_dashboard_button_name(self): - super(Team,self)._compute_dashboard_button_name() + super(Team, self)._compute_dashboard_button_name() team_with_pipelines = self.filtered(lambda el: el.use_opportunities) team_with_pipelines.update({'dashboard_button_name': _("Pipeline")}) diff --git a/addons/crm/report/crm_opportunity_report_views.xml b/addons/crm/report/crm_opportunity_report_views.xml index cf6eec4bfc7..1d6972d0aaf 100644 --- a/addons/crm/report/crm_opportunity_report_views.xml +++ b/addons/crm/report/crm_opportunity_report_views.xml @@ -123,11 +123,9 @@ teams of the sales pipeline. - + + + Leads Analysis @@ -142,12 +140,8 @@ This report analyses the source of your leads. - + + + diff --git a/addons/crm/tests/common.py b/addons/crm/tests/common.py index c1171e4c44d..ce936bb2e3b 100644 --- a/addons/crm/tests/common.py +++ b/addons/crm/tests/common.py @@ -4,8 +4,8 @@ from unittest.mock import patch from odoo.addons.mail.tests.common import MailCase, mail_new_test_user +from odoo.addons.sales_team.tests.common import TestSalesCommon from odoo.fields import Datetime -from odoo.tests.common import SavepointCase INCOMING_EMAIL = """Return-Path: {return_path} X-Original-To: {to} @@ -39,43 +39,21 @@ Cheers, Somebody.""" -class TestCrmCommon(SavepointCase, MailCase): +class TestCrmCommon(TestSalesCommon, MailCase): @classmethod def setUpClass(cls): super(TestCrmCommon, cls).setUpClass() cls._init_mail_gateway() - cls.user_sales_manager = mail_new_test_user( - cls.env, login='user_sales_manager', - name='Martin Sales Manager', email='crm_manager@test.example.com', - company_id=cls.env.ref("base.main_company").id, - notification_type='inbox', - groups='sales_team.group_sale_manager,base.group_partner_manager,crm.group_use_lead', - ) - cls.user_sales_leads = mail_new_test_user( - cls.env, login='user_sales_leads', - name='Laetitia Sales Leads', email='crm_leads@test.example.com', - company_id=cls.env.ref("base.main_company").id, - notification_type='inbox', - groups='sales_team.group_sale_salesman_all_leads,base.group_partner_manager,crm.group_use_lead', - ) - cls.user_sales_salesman = mail_new_test_user( - cls.env, login='user_sales_salesman', - name='Orteil Sales Own', email='crm_salesman@test.example.com', - company_id=cls.env.ref("base.main_company").id, - notification_type='inbox', - groups='sales_team.group_sale_salesman,crm.group_use_lead', - ) - - cls.sales_team_1 = cls.env['crm.team'].create({ - 'name': 'Test Sales Team', + cls.sales_team_1.write({ 'alias_name': 'sales.test', 'use_leads': True, 'use_opportunities': True, - 'company_id': False, - 'user_id': cls.user_sales_manager.id, - 'member_ids': [(4, cls.user_sales_leads.id), (4, cls.env.ref('base.user_admin').id)], + }) + + (cls.user_sales_manager | cls.user_sales_leads | cls.user_sales_salesman).write({ + 'groups_id': [(4, cls.env.ref('crm.group_use_lead').id)] }) cls.env['crm.stage'].search([]).write({'sequence': 9999}) # ensure search will find test data first diff --git a/addons/crm/views/crm_templates.xml b/addons/crm/views/assets.xml similarity index 100% rename from addons/crm/views/crm_templates.xml rename to addons/crm/views/assets.xml diff --git a/addons/crm/views/calendar_views.xml b/addons/crm/views/calendar_views.xml index b82569b1845..8267a60558d 100644 --- a/addons/crm/views/calendar_views.xml +++ b/addons/crm/views/calendar_views.xml @@ -1,11 +1,6 @@ - - calendar.event.form.inherit calendar.event diff --git a/addons/crm/views/crm_lead_views.xml b/addons/crm/views/crm_lead_views.xml index b7d86291efb..5edbfb84020 100644 --- a/addons/crm/views/crm_lead_views.xml +++ b/addons/crm/views/crm_lead_views.xml @@ -767,28 +767,6 @@ if record: - - - - - - - Leads @@ -839,12 +817,9 @@ if record: - + + + @@ -948,22 +923,10 @@ if record: - - - - - + + + + + + diff --git a/addons/crm/views/crm_lost_reason_views.xml b/addons/crm/views/crm_lost_reason_views.xml index 7f65379bcc0..33986e14da8 100644 --- a/addons/crm/views/crm_lost_reason_views.xml +++ b/addons/crm/views/crm_lost_reason_views.xml @@ -69,9 +69,7 @@ - + + + diff --git a/addons/crm/views/crm_menu_views.xml b/addons/crm/views/crm_menu_views.xml index cbcfe85b201..e679fb8f122 100644 --- a/addons/crm/views/crm_menu_views.xml +++ b/addons/crm/views/crm_menu_views.xml @@ -1,26 +1,126 @@ - + - - + + + - + + + + + - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + diff --git a/addons/crm/views/crm_stage_views.xml b/addons/crm/views/crm_stage_views.xml index 95e2a321990..2dc3a4c7c10 100644 --- a/addons/crm/views/crm_stage_views.xml +++ b/addons/crm/views/crm_stage_views.xml @@ -71,12 +71,8 @@ - + + + diff --git a/addons/crm/views/crm_team_views.xml b/addons/crm/views/crm_team_views.xml index 90301bc7385..a1981660cc3 100644 --- a/addons/crm/views/crm_team_views.xml +++ b/addons/crm/views/crm_team_views.xml @@ -268,9 +268,4 @@ - - ['|', ('res_model_id', '=', False), ('res_model_id.model', 'in', ['crm.lead', 'res.partner'])] - {'default_res_model': 'crm.lead'} - - diff --git a/addons/crm/views/crm_views.xml b/addons/crm/views/crm_views.xml deleted file mode 100644 index 59a07dfb804..00000000000 --- a/addons/crm/views/crm_views.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/addons/crm/views/mail_activity_views.xml b/addons/crm/views/mail_activity_views.xml new file mode 100644 index 00000000000..6b489ee8807 --- /dev/null +++ b/addons/crm/views/mail_activity_views.xml @@ -0,0 +1,7 @@ + + + + ['|', ('res_model_id', '=', False), ('res_model_id.model', 'in', ['crm.lead', 'res.partner'])] + {'default_res_model': 'crm.lead'} + + diff --git a/addons/crm/views/res_config_settings_views.xml b/addons/crm/views/res_config_settings_views.xml index f0cabe5d527..d2ff6b19c98 100644 --- a/addons/crm/views/res_config_settings_views.xml +++ b/addons/crm/views/res_config_settings_views.xml @@ -133,4 +133,9 @@ inline {'module' : 'crm'} + + + + + diff --git a/addons/sales_team/__manifest__.py b/addons/sales_team/__manifest__.py index 39fae18b93c..d856467e068 100644 --- a/addons/sales_team/__manifest__.py +++ b/addons/sales_team/__manifest__.py @@ -1,26 +1,30 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. + { 'name': 'Sales Teams', 'version': '1.0', 'category': 'Sales/Sales', 'summary': 'Sales Teams', 'description': """ -Using this application you can manage Sales Teams with CRM and/or Sales -=========================================================================== +Using this application you can manage Sales Teams with CRM and/or Sales +======================================================================= """, 'website': 'https://www.odoo.com/page/crm', 'depends': ['base', 'mail'], - 'data': ['security/sales_team_security.xml', - 'security/ir.model.access.csv', - 'data/sales_team_data.xml', - 'views/crm_team_views.xml', - 'views/sales_team_dashboard.xml', - 'views/crm_tag_views.xml', - ], - 'demo': ['data/sales_team_demo.xml', - 'data/crm_tag_demo.xml', - ], + 'data': [ + 'security/sales_team_security.xml', + 'security/ir.model.access.csv', + 'data/crm_team_data.xml', + 'views/assets.xml', + 'views/crm_tag_views.xml', + 'views/crm_team_views.xml', + 'views/mail_activity_views.xml', + ], + 'demo': [ + 'data/crm_team_demo.xml', + 'data/crm_tag_demo.xml', + ], 'installable': True, 'auto_install': False, } diff --git a/addons/sales_team/data/crm_tag_demo.xml b/addons/sales_team/data/crm_tag_demo.xml index 4b409e0bf27..85d61b063ea 100644 --- a/addons/sales_team/data/crm_tag_demo.xml +++ b/addons/sales_team/data/crm_tag_demo.xml @@ -1,39 +1,38 @@ - - + - - - Product - - - - Software - - - - Services - - - - Information - - - - Design - - - - Training - - - - Consulting - - - - Other - - - - + + + Product + + + + Software + + + + Services + + + + Information + + + + Design + + + + Training + + + + Consulting + + + + Other + + + + diff --git a/addons/sales_team/data/sales_team_data.xml b/addons/sales_team/data/crm_team_data.xml similarity index 100% rename from addons/sales_team/data/sales_team_data.xml rename to addons/sales_team/data/crm_team_data.xml diff --git a/addons/sales_team/data/sales_team_demo.xml b/addons/sales_team/data/crm_team_demo.xml similarity index 100% rename from addons/sales_team/data/sales_team_demo.xml rename to addons/sales_team/data/crm_team_demo.xml diff --git a/addons/sales_team/models/crm_team.py b/addons/sales_team/models/crm_team.py index 4b84837c506..ef919653fea 100644 --- a/addons/sales_team/models/crm_team.py +++ b/addons/sales_team/models/crm_team.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - -from babel.dates import format_date -from datetime import date, datetime -from dateutil.relativedelta import relativedelta import json +from babel.dates import format_date +from datetime import date +from dateutil.relativedelta import relativedelta + from odoo import api, fields, models, _ -from odoo.exceptions import AccessError, UserError +from odoo.exceptions import UserError from odoo.release import version -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF class CrmTeam(models.Model): @@ -38,32 +37,29 @@ class CrmTeam(models.Model): name = fields.Char('Sales Team', required=True, translate=True) sequence = fields.Integer('Sequence', default=10) active = fields.Boolean(default=True, help="If the active field is set to false, it will allow you to hide the Sales Team without removing it.") - company_id = fields.Many2one('res.company', string='Company', - default=lambda self: self.env.company, index=True) + company_id = fields.Many2one( + 'res.company', string='Company', index=True, + default=lambda self: self.env.company) currency_id = fields.Many2one( - "res.currency", related='company_id.currency_id', - string="Currency", readonly=True) + "res.currency", string="Currency", + related='company_id.currency_id', readonly=True) user_id = fields.Many2one('res.users', string='Team Leader', check_company=True) + # memberships member_ids = fields.One2many( - 'res.users', 'sale_team_id', string='Channel Members', check_company=True, - domain=[('share', '=', False)], + 'res.users', 'sale_team_id', string='Channel Members', + check_company=True, domain=[('share', '=', False)], help="Add members to automatically assign their documents to this sales team. You can only be member of one team.") + # UX options + color = fields.Integer(string='Color Index', help="The color of the channel") favorite_user_ids = fields.Many2many( 'res.users', 'team_favorite_user_rel', 'team_id', 'user_id', - string='Favorite Members', - default=_get_default_favorite_user_ids) + string='Favorite Members', default=_get_default_favorite_user_ids) is_favorite = fields.Boolean( - string='Show on dashboard', - compute='_compute_is_favorite', inverse='_inverse_is_favorite', + string='Show on dashboard', compute='_compute_is_favorite', inverse='_inverse_is_favorite', help="Favorite teams to display them in the dashboard and access them easily.") - color = fields.Integer(string='Color Index', help="The color of the channel") dashboard_button_name = fields.Char(string="Dashboard Button", compute='_compute_dashboard_button_name') dashboard_graph_data = fields.Text(compute='_compute_dashboard_graph') - def _compute_dashboard_graph(self): - for team in self: - team.dashboard_graph_data = json.dumps(team._get_graph()) - def _compute_is_favorite(self): for team in self: team.is_favorite = self.env.user in team.favorite_user_ids @@ -75,6 +71,65 @@ class CrmTeam(models.Model): (sudoed_self - to_fav).write({'favorite_user_ids': [(3, self.env.uid)]}) return True + def _compute_dashboard_button_name(self): + """ Sets the adequate dashboard button name depending on the Sales Team's options + """ + for team in self: + team.dashboard_button_name = _("Big Pretty Button :)") # placeholder + + def _compute_dashboard_graph(self): + for team in self: + team.dashboard_graph_data = json.dumps(team._get_dashboard_graph_data()) + + # ------------------------------------------------------------ + # CRUD + # ------------------------------------------------------------ + + @api.model + def create(self, values): + team = super(CrmTeam, self.with_context(mail_create_nosubscribe=True)).create(values) + if values.get('member_ids'): + team._add_members_to_favorites() + return team + + def write(self, values): + res = super(CrmTeam, self).write(values) + if values.get('member_ids'): + self._add_members_to_favorites() + return res + + def unlink(self): + default_teams = [ + self.env.ref('sales_team.salesteam_website_sales'), + self.env.ref('sales_team.pos_sales_team'), + self.env.ref('sales_team.ebay_sales_team') + ] + for team in self: + if team in default_teams: + raise UserError(_('Cannot delete default team "%s"' % (team.name))) + return super(CrmTeam,self).unlink() + + # ------------------------------------------------------------ + # ACTIONS + # ------------------------------------------------------------ + + def action_primary_channel_button(self): + """ Skeleton function to be overloaded It will return the adequate action + depending on the Sales Team's options. """ + return False + + # ------------------------------------------------------------ + # TOOLS + # ------------------------------------------------------------ + + def _add_members_to_favorites(self): + for team in self: + team.favorite_user_ids = [(4, member.id) for member in team.member_ids] + + # ------------------------------------------------------------ + # GRAPH + # ------------------------------------------------------------ + def _graph_get_model(self): """ skeleton function defined here because it'll be called by crm and/or sale """ @@ -146,7 +201,7 @@ class CrmTeam(models.Model): self._cr.execute(query, [self.id, start_date, end_date] + where_clause_params) return self.env.cr.dictfetchall() - def _get_graph(self): + def _get_dashboard_graph_data(self): def get_week_name(start_date, locale): """ Generates a week name (string) from a datetime according to the locale: E.g.: locale start_date (datetime) return string @@ -183,43 +238,3 @@ class CrmTeam(models.Model): [graph_title, graph_key] = self._graph_title_and_key() color = '#875A7B' if '+e' in version else '#7c7bad' return [{'values': values, 'area': True, 'title': graph_title, 'key': graph_key, 'color': color}] - - def _compute_dashboard_button_name(self): - """ Sets the adequate dashboard button name depending on the Sales Team's options - """ - for team in self: - team.dashboard_button_name = _("Big Pretty Button :)") # placeholder - - def action_primary_channel_button(self): - """ skeleton function to be overloaded - It will return the adequate action depending on the Sales Team's options - """ - return False - - @api.model - def create(self, values): - team = super(CrmTeam, self.with_context(mail_create_nosubscribe=True)).create(values) - if values.get('member_ids'): - team._add_members_to_favorites() - return team - - def write(self, values): - res = super(CrmTeam, self).write(values) - if values.get('member_ids'): - self._add_members_to_favorites() - return res - - def unlink(self): - default_teams = [ - self.env.ref('sales_team.salesteam_website_sales'), - self.env.ref('sales_team.pos_sales_team'), - self.env.ref('sales_team.ebay_sales_team') - ] - for team in self: - if team in default_teams: - raise UserError(_('Cannot delete default team "%s"' % (team.name))) - return super(CrmTeam,self).unlink() - - def _add_members_to_favorites(self): - for team in self: - team.favorite_user_ids = [(4, member.id) for member in team.member_ids] diff --git a/addons/sales_team/models/res_users.py b/addons/sales_team/models/res_users.py index 0714af03dce..f2fdd18337a 100644 --- a/addons/sales_team/models/res_users.py +++ b/addons/sales_team/models/res_users.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, fields, models +from odoo import fields, models class ResUsers(models.Model): diff --git a/addons/sales_team/tests/__init__.py b/addons/sales_team/tests/__init__.py index 7bb8a11fc5e..828034121fe 100644 --- a/addons/sales_team/tests/__init__.py +++ b/addons/sales_team/tests/__init__.py @@ -1 +1,5 @@ -from . import test_default_team +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import common +from . import test_sales_team_membership diff --git a/addons/sales_team/tests/common.py b/addons/sales_team/tests/common.py new file mode 100644 index 00000000000..a06f97c02c2 --- /dev/null +++ b/addons/sales_team/tests/common.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.mail.tests.common import mail_new_test_user +from odoo.tests.common import SavepointCase + + +class TestSalesCommon(SavepointCase): + + @classmethod + def setUpClass(cls): + super(TestSalesCommon, cls).setUpClass() + + cls.company_main = cls.env.user.company_id + cls.user_sales_manager = mail_new_test_user( + cls.env, login='user_sales_manager', + name='Martin Sales Manager', email='crm_manager@test.example.com', + company_id=cls.company_main.id, + notification_type='inbox', + groups='sales_team.group_sale_manager,base.group_partner_manager', + ) + cls.user_sales_leads = mail_new_test_user( + cls.env, login='user_sales_leads', + name='Laetitia Sales Leads', email='crm_leads@test.example.com', + company_id=cls.company_main.id, + notification_type='inbox', + groups='sales_team.group_sale_salesman_all_leads,base.group_partner_manager', + ) + cls.user_sales_salesman = mail_new_test_user( + cls.env, login='user_sales_salesman', + name='Orteil Sales Own', email='crm_salesman@test.example.com', + company_id=cls.company_main.id, + notification_type='inbox', + groups='sales_team.group_sale_salesman', + ) + + cls.env['crm.team'].search([]).write({'sequence': 9999}) + cls.sales_team_1 = cls.env['crm.team'].create({ + 'name': 'Test Sales Team', + 'sequence': 5, + 'company_id': False, + 'user_id': cls.user_sales_manager.id, + 'member_ids': [(4, cls.user_sales_leads.id), (4, cls.env.ref('base.user_admin').id)], + }) + + +class TestSalesMC(TestSalesCommon): + """ Multi Company / Multi Sales Team environment """ + + @classmethod + def setUpClass(cls): + super(TestSalesMC, cls).setUpClass() + cls.company_2 = cls.env['res.company'].create({ + 'name': 'New Test Company', + 'email': 'company.2@test.example.com', + 'country_id': cls.env.ref('base.fr'), + }) + cls.team_c2 = cls.env['crm.team'].create({ + 'name': 'C2 Team1', + 'sequence': 1, + 'company_id': cls.company_2.id, + }) diff --git a/addons/sales_team/tests/test_default_team.py b/addons/sales_team/tests/test_default_team.py deleted file mode 100644 index 8d7b24d0357..00000000000 --- a/addons/sales_team/tests/test_default_team.py +++ /dev/null @@ -1,53 +0,0 @@ -from odoo.tests import common - - -class TestDefaultTeam(common.SavepointCase): - """Tests to check if correct default team is found.""" - - @classmethod - def setUpClass(cls): - """Set up data for default team tests.""" - super(TestDefaultTeam, cls).setUpClass() - cls.CrmTeam = cls.env['crm.team'] - ResUsers = cls.env['res.users'].with_context( - {'no_reset_password': True}) - group_sale_manager = cls.env.ref('sales_team.group_sale_manager') - cls.user = ResUsers.create({ - 'name': 'Team User', - 'login': 'sales_team_user', - 'email': 'sales.team.user@example.com', - 'groups_id': [(6, 0, [group_sale_manager.id])] - }) - cls.team_1 = cls.env['crm.team'].create({ - 'name': 'Test Team', - 'member_ids': [(4, cls.user.id)], - 'company_id': False - }) - # Europe Team (fall back team) - cls.team_2 = cls.env.ref('sales_team.team_sales_department') - cls.team_3 = cls.env['crm.team'].create({ - 'name': 'Team 3', - 'sequence': 2, - 'company_id': False - }) - - def test_01_user_team(self): - """Get default team, when user belongs to one.""" - team = self.CrmTeam.with_user(self.user)._get_default_team_id() - self.assertEqual(team, self.team_1) - - def test_02_fallback_team(self): - """Get default team when user does not belong to any team. - - Case 1: fall back default team (from XML ref) is active. - Case 2: fall back default team is not active. - """ - # Clear users from team. - self.team_1.member_ids = [(5,)] - # Case 1. - team = self.CrmTeam.with_user(self.user)._get_default_team_id() - self.assertEqual(team, self.team_2) - # Case 2. If default team is not active, fall back is the next team with the higher sequence - self.team_2.active = False - team = self.CrmTeam.with_user(self.user)._get_default_team_id() - self.assertEqual(team, self.team_3) diff --git a/addons/sales_team/tests/test_sales_team_membership.py b/addons/sales_team/tests/test_sales_team_membership.py new file mode 100644 index 00000000000..8e08178915f --- /dev/null +++ b/addons/sales_team/tests/test_sales_team_membership.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.sales_team.tests.common import TestSalesMC + + +class TestDefaultTeam(TestSalesMC): + """Tests to check if correct default team is found.""" + + @classmethod + def setUpClass(cls): + """Set up data for default team tests.""" + super(TestDefaultTeam, cls).setUpClass() + + cls.team_sequence = cls.env['crm.team'].create({ + 'name': 'Team LowSequence', + 'sequence': 0, + 'company_id': False, + }) + cls.team_responsible = cls.env['crm.team'].create({ + 'name': 'Team 3', + 'user_id': cls.user_sales_manager.id, + 'sequence': 3, + 'company_id': cls.company_main.id + }) + + def test_default_team_member(self): + with self.with_user('user_sales_leads'): + team = self.env['crm.team']._get_default_team_id() + self.assertEqual(team, self.sales_team_1) + + # responsible with lower sequence better than member with higher sequence + self.team_responsible.user_id = self.user_sales_leads.id + with self.with_user('user_sales_leads'): + team = self.env['crm.team']._get_default_team_id() + self.assertEqual(team, self.team_responsible) + + def test_default_team_fallback(self): + """ Test fallback: domain, order """ + self.sales_team_1.member_ids = [(5,)] + + with self.with_user('user_sales_leads'): + team = self.env['crm.team']._get_default_team_id() + self.assertEqual(team, self.team_sequence) + + # next one is team_responsible with sequence = 3 (team_c2 is in another company) + self.team_sequence.active = False + with self.with_user('user_sales_leads'): + team = self.env['crm.team']._get_default_team_id() + self.assertEqual(team, self.team_responsible) + + self.user_sales_leads.write({ + 'company_ids': [(4, self.company_2.id)], + 'company_id': self.company_2.id, + }) + # multi company: switch company + self.user_sales_leads.write({'company_id': self.company_2.id}) + with self.with_user('user_sales_leads'): + team = self.env['crm.team']._get_default_team_id() + self.assertEqual(team, self.team_c2) diff --git a/addons/sales_team/views/assets.xml b/addons/sales_team/views/assets.xml new file mode 100644 index 00000000000..3331b7cf4c1 --- /dev/null +++ b/addons/sales_team/views/assets.xml @@ -0,0 +1,8 @@ + + + + diff --git a/addons/sales_team/views/crm_team_views.xml b/addons/sales_team/views/crm_team_views.xml index 008a40f7d0c..f495e5cd62d 100644 --- a/addons/sales_team/views/crm_team_views.xml +++ b/addons/sales_team/views/crm_team_views.xml @@ -1,182 +1,244 @@ - - + - - - Sales Teams - Search - crm.team - - - - - - - - - - - + + Sales Teams - Search + crm.team + + + + + + + + + + + - - - Sales Teams - crm.team - kanban,form - - {'in_sales_app': True} - -

- Define a new sales team -

- Use Sales Teams to organize your sales departments. - Each team will work with a separate pipeline. -

-
-
- - - Team Pipelines - crm.team - kanban,form - - {} - -

- Define a new sales team -

- Use Sales Teams to organize your sales departments. - Each team will work with a separate pipeline. -

-
-
- - - - - crm.team.form - crm.team - -
- -
- -
-