[ADD]: Multi branch and CRM.
This commit is contained in:
parent
06065498bc
commit
cb7bf9524f
4
addons/base_branch_company/__init__.py
Normal file
4
addons/base_branch_company/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import models
|
35
addons/base_branch_company/__manifest__.py
Normal file
35
addons/base_branch_company/__manifest__.py
Normal file
@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
{
|
||||
'name': 'Branch & Company Mixin',
|
||||
'version': '1.0',
|
||||
'category': 'Discuss',
|
||||
'author': ['Flectra'],
|
||||
'sequence': 25,
|
||||
'summary': 'Include Branch & Company support',
|
||||
'description': """
|
||||
Branch & Company
|
||||
================
|
||||
|
||||
Main Features
|
||||
-------------
|
||||
* Include Branch & Company in all objects
|
||||
* Just need to inherit ir.branch.company.mixin in your object
|
||||
* And in your xml file add below 2 lines in your Views
|
||||
<field name="branch_id" />
|
||||
<field name="company_id" />
|
||||
""",
|
||||
'website': '',
|
||||
'depends': ['base'],
|
||||
'data': [
|
||||
'security/branch_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'views/res_branch_view.xml',
|
||||
],
|
||||
'demo': [
|
||||
'demo/branch_demo.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'auto_install': True
|
||||
}
|
42
addons/base_branch_company/demo/branch_demo.xml
Normal file
42
addons/base_branch_company/demo/branch_demo.xml
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
|
||||
|
||||
<record id="data_branch_1" model="res.branch">
|
||||
<field name="name">New York</field>
|
||||
<field name="code">NY</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="street">80 Broad St</field>
|
||||
<field name="city">Scranton</field>
|
||||
<field name="zip">10004</field>
|
||||
<field name='country_id' ref='base.us'/>
|
||||
<field name='state_id' ref='base.state_us_27'/>
|
||||
<field name="phone">+1 485 123 8989</field>
|
||||
</record>
|
||||
<record id="data_branch_2" model="res.branch">
|
||||
<field name="name">Washington</field>
|
||||
<field name="code">WA</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="street">2050 Bamako Place</field>
|
||||
<field name="zip">DC 20521-7100</field>
|
||||
<field name='country_id' ref='base.us'/>
|
||||
<field name='state_id' ref='base.state_us_48'/>
|
||||
<field name="phone">+1 555 123 8069</field>
|
||||
</record>
|
||||
<record id="data_branch_3" model="res.branch">
|
||||
<field name="name">New Jersey</field>
|
||||
<field name="code">NJ</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="street">2711-2880 Nulla St.</field>
|
||||
<field name="zip">NJ 20521-7100</field>
|
||||
<field name='country_id' ref='base.us'/>
|
||||
<field name='state_id' ref='base.state_us_48'/>
|
||||
<field name="phone">(372) 587-2335</field>
|
||||
</record>
|
||||
<record id="base.user_root" model="res.users">
|
||||
<field name="branch_ids" eval="[(6,0,[ref('data_branch_1'),])]"/>
|
||||
<field name='default_branch_id' ref='data_branch_1'/>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
8
addons/base_branch_company/models/__init__.py
Normal file
8
addons/base_branch_company/models/__init__.py
Normal file
@ -0,0 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
|
||||
from . import res_branch
|
||||
from . import ir_branch_company
|
||||
from . import res_partner
|
||||
|
15
addons/base_branch_company/models/ir_branch_company.py
Normal file
15
addons/base_branch_company/models/ir_branch_company.py
Normal file
@ -0,0 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import fields, models
|
||||
|
||||
|
||||
class IrBranchCompanyMixin(models.AbstractModel):
|
||||
_name = "ir.branch.company.mixin"
|
||||
|
||||
branch_id = fields.Many2one(
|
||||
'res.branch', 'Branch', ondelete="restrict",
|
||||
default=lambda self: self.env.user.default_branch_id)
|
||||
company_id = fields.Many2one(
|
||||
'res.company', 'Company', ondelete="restrict",
|
||||
default=lambda self: self.env.user.company_id)
|
105
addons/base_branch_company/models/res_branch.py
Normal file
105
addons/base_branch_company/models/res_branch.py
Normal file
@ -0,0 +1,105 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from flectra import api, fields, models
|
||||
|
||||
|
||||
class Company(models.Model):
|
||||
_name = "res.company"
|
||||
_inherit = ["res.company"]
|
||||
|
||||
branch_id = fields.Many2one('res.branch', 'Branch', ondelete="restrict")
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
branch = self.env['res.branch'].create({
|
||||
'name': vals['name'],
|
||||
'code': vals['name'],
|
||||
})
|
||||
vals['branch_id'] = branch.id
|
||||
self.clear_caches()
|
||||
company = super(Company, self).create(vals)
|
||||
branch.write({'partner_id': company.partner_id.id,
|
||||
'company_id': company.id})
|
||||
return company
|
||||
|
||||
class ResBranch(models.Model):
|
||||
_name = "res.branch"
|
||||
|
||||
name = fields.Char(string='Name', required=True)
|
||||
code = fields.Char(string='Code', required=True)
|
||||
active = fields.Boolean(string='Active', default=True)
|
||||
partner_id = fields.Many2one('res.partner', string='Partner',
|
||||
ondelete='restrict')
|
||||
company_id = fields.Many2one(
|
||||
'res.company', string="Company",
|
||||
default=lambda self: self.env.user.company_id, required=True)
|
||||
street = fields.Char()
|
||||
street2 = fields.Char()
|
||||
zip = fields.Char(change_default=True)
|
||||
city = fields.Char()
|
||||
state_id = fields.Many2one("res.country.state", string='State',
|
||||
ondelete='restrict')
|
||||
country_id = fields.Many2one('res.country', string='Country',
|
||||
ondelete='restrict')
|
||||
email = fields.Char()
|
||||
phone = fields.Char()
|
||||
mobile = fields.Char()
|
||||
|
||||
_sql_constraints = [('branch_code_company_uniq', 'unique (code,company_id)',
|
||||
'The branch code must be unique per company!')]
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if not vals.get('partner_id', False):
|
||||
partner_id = self.env['res.partner'].create({'name': vals['name']})
|
||||
vals.update({'partner_id': partner_id.id})
|
||||
res = super(ResBranch, self).create(vals)
|
||||
vals.pop("name", None)
|
||||
vals.pop("code", None)
|
||||
vals.pop("partner_id", None)
|
||||
vals.update({'branch_id': res.id})
|
||||
res.partner_id.write(vals)
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
res = super(ResBranch, self).write(vals)
|
||||
vals.pop("name", None)
|
||||
vals.pop("code", None)
|
||||
vals.pop("company_id", None)
|
||||
vals.pop("partner_id", None)
|
||||
ctx = self.env.context.copy()
|
||||
if 'branch' not in ctx:
|
||||
self.partner_id.write(vals)
|
||||
return res
|
||||
|
||||
|
||||
class Users(models.Model):
|
||||
|
||||
_inherit = "res.users"
|
||||
|
||||
@api.model
|
||||
def branch_default_get(self, user):
|
||||
if not user:
|
||||
user = self._uid
|
||||
branch_id = self.env['res.users'].browse(user).default_branch_id
|
||||
if not branch_id:
|
||||
branch_id = \
|
||||
self.env['res.users'].browse(user).company_id.branch_id
|
||||
return branch_id
|
||||
|
||||
@api.model
|
||||
def _get_default_branch(self):
|
||||
return self.branch_default_get(self._uid)
|
||||
|
||||
branch_ids = fields.Many2many('res.branch',
|
||||
'res_branch_users_rel',
|
||||
'user_id',
|
||||
'branch_id',
|
||||
'Branches')
|
||||
default_branch_id = fields.Many2one('res.branch', 'Default branch',
|
||||
default=_get_default_branch,
|
||||
domain="[('company_id','=',company_id)"
|
||||
"]")
|
||||
|
||||
|
22
addons/base_branch_company/models/res_partner.py
Normal file
22
addons/base_branch_company/models/res_partner.py
Normal file
@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from flectra import api, fields, models
|
||||
|
||||
class Partner(models.Model):
|
||||
_name = "res.partner"
|
||||
_inherit = ["res.partner", "ir.branch.company.mixin"]
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
field_list = ['street', 'street2', 'zip', 'city', 'state_id',
|
||||
'country_id', 'email', 'phone', 'mobile']
|
||||
branch_vals = dict((f, vals[f]) for f in field_list if f in vals)
|
||||
if branch_vals and self.branch_id:
|
||||
ctx = self.env.context.copy()
|
||||
ctx.update({'branch': True})
|
||||
self.branch_id.with_context(ctx).write(branch_vals)
|
||||
result = super(Partner, self).write(vals)
|
||||
return result
|
||||
|
||||
|
||||
|
20
addons/base_branch_company/security/branch_security.xml
Normal file
20
addons/base_branch_company/security/branch_security.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra noupdate="1">
|
||||
|
||||
<record id="branch_comp_rule" model="ir.rule">
|
||||
<field name="name">Branch</field>
|
||||
<field name="model_id" ref="model_res_branch"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_rule_branch_allowed"
|
||||
model="ir.rule">
|
||||
<field name="model_id" ref="model_res_branch"/>
|
||||
<field name="domain_force">['|', ('id','=',user.default_branch_id.id), ('id','in',[g.id for g in user.branch_ids])]
|
||||
</field>
|
||||
<field name="name">Allowed Branch</field>
|
||||
<field name="global" eval="True"/>
|
||||
</record>
|
||||
|
||||
</flectra>
|
3
addons/base_branch_company/security/ir.model.access.csv
Normal file
3
addons/base_branch_company/security/ir.model.access.csv
Normal file
@ -0,0 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_res_branch,access_res_branch,model_res_branch,,1,1,1,0
|
||||
access_ir_branch_company,access_ir_branch_company,model_ir_branch_company_mixin,,1,1,1,0
|
|
1
addons/base_branch_company/tests/__init__.py
Normal file
1
addons/base_branch_company/tests/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from . import test_branch
|
80
addons/base_branch_company/tests/test_branch.py
Normal file
80
addons/base_branch_company/tests/test_branch.py
Normal file
@ -0,0 +1,80 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra.tests.common import TransactionCase
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class TestMultiBranch(TransactionCase):
|
||||
def setUp(self):
|
||||
super(TestMultiBranch, self).setUp()
|
||||
self.partner_obj = self.env['res.partner']
|
||||
self.main_company = self.env.ref('base.main_company')
|
||||
|
||||
self.branch0 = self.env.ref('base_branch_company.data_branch_1')
|
||||
self.branch1 = self.env.ref('base_branch_company.data_branch_2')
|
||||
|
||||
self.user_1 = self.create_user(self.main_company, 'user_1', self.branch0,
|
||||
[self.branch0, self.branch1])
|
||||
self.user_2 = self.create_user(self.main_company, 'user_2', self.branch1,
|
||||
[self.branch1])
|
||||
|
||||
self.model_id = \
|
||||
self.env['ir.model'].search([('model', '=', 'res.partner')])
|
||||
self.record_rules = self.env['ir.rule'].create({
|
||||
'name': 'Partner',
|
||||
'model_id': self.model_id.id,
|
||||
'domain_force':
|
||||
"['|',('branch_id','=', False),'|', "
|
||||
"('branch_id','=',user.default_branch_id.id), "
|
||||
"('branch_id','in', [b.id for b in user.branch_ids] )]"
|
||||
})
|
||||
self.branch_partner0 = self.partner_obj.create({
|
||||
'name': 'Test Partner0',
|
||||
'email': 'test@123.example.com',
|
||||
'branch_id': self.branch0.id
|
||||
})
|
||||
|
||||
self.env = self.env(user=self.user_1)
|
||||
self.branch_partner1 = self.partner_obj.create({
|
||||
'name': 'Test Partner1',
|
||||
'email': 'test@123.example.com',
|
||||
'branch_id': self.branch0.id
|
||||
})
|
||||
|
||||
def create_user(self, main_company, user_name, branch_id, branch_ids):
|
||||
data = {
|
||||
'company_ids': [(4, main_company.id)],
|
||||
'branch_ids': [(4, branch_id.id) for branch_id in branch_ids],
|
||||
'company_id': main_company.id,
|
||||
'default_branch_id': branch_id.id,
|
||||
'login': user_name,
|
||||
'name': 'Test User',
|
||||
'password': '123',
|
||||
'email': 'testuser@yourcompany.com',
|
||||
|
||||
}
|
||||
user_obj = self.env['res.users'].create(data)
|
||||
return user_obj
|
||||
|
||||
|
||||
def test_user_authentication(self):
|
||||
partner = self.partner_obj.sudo(self.user_1.id).search(
|
||||
[('id', '=', self.branch_partner1.id),
|
||||
('branch_id', '=', self.branch0.id)])
|
||||
self.assertNotEqual(partner.ids, [], 'Test User have access to '
|
||||
'Branch %s' % self.branch0.name)
|
||||
|
||||
partner = self.partner_obj.sudo(self.user_2.id).search(
|
||||
[('id', '=', self.branch_partner0.id),
|
||||
('branch_id', '=', self.branch0.id)])
|
||||
self.assertEqual(partner.ids, [],
|
||||
'Test User should not have access to '
|
||||
'Branch %s' % self.branch0.name)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
106
addons/base_branch_company/views/res_branch_view.xml
Normal file
106
addons/base_branch_company/views/res_branch_view.xml
Normal file
@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<record id="view_res_branch_form" model="ir.ui.view">
|
||||
<field name="name">res.branch.form</field>
|
||||
<field name="model">res.branch</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Branch">
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="toggle_active" type="object"
|
||||
class="oe_stat_button" icon="fa-archive">
|
||||
<field name="active" widget="boolean_button"
|
||||
options='{"terminology": "archive"}'/>
|
||||
</button>
|
||||
</div>
|
||||
<group col="4">
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="partner_id" readonly="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<label for="street" string="Address"/>
|
||||
<div class="o_address_format">
|
||||
<field name="street" placeholder="Street..." class="o_address_street"/>
|
||||
<field name="street2" placeholder="Street 2..." class="o_address_street"/>
|
||||
<field name="city" placeholder="City" class="o_address_city"/>
|
||||
<field name="state_id" class="o_address_state" placeholder="State" options='{"no_open": True}'
|
||||
context="{'country_id': country_id, 'zip': zip}"/>
|
||||
<field name="zip" placeholder="ZIP" class="o_address_zip"/>
|
||||
<field name="country_id" placeholder="Country" class="o_address_country" options='{"no_open": True, "no_create": True}'/>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<field name="phone" widget="phone"/>
|
||||
<field name="mobile" widget="phone"/>
|
||||
<field name="email" widget="email" context="{'gravatar_image': True}"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_res_branch_tree" model="ir.ui.view">
|
||||
<field name="name">res.branch.tree</field>
|
||||
<field name="model">res.branch</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Branch">
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_res_branch_search" model="ir.ui.view">
|
||||
<field name="name">res.branch.search</field>
|
||||
<field name="model">res.branch</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Branch">
|
||||
<field name="name" string="Branch"/>
|
||||
<field name="code" string="Code"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_res_branch_tree" model="ir.actions.act_window">
|
||||
<field name="name">Branches</field>
|
||||
<field name="res_model">res.branch</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to start a new Branch.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_res_branch_tree"
|
||||
id="menu_action_res_branch_tree"
|
||||
parent="base.menu_users"/>
|
||||
|
||||
|
||||
<record id="view_branch_users_form" model="ir.ui.view">
|
||||
<field name="name">res.users.form.branch</field>
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='access_rights']/group[1]" position="replace">
|
||||
<group>
|
||||
<group string="Multi Companies" attrs="{'invisible': [('companies_count', '<=', 1)]}">
|
||||
<field string="Allowed Companies" name="company_ids" widget="many2many_tags"/>
|
||||
<field string="Current Company" name="company_id" context="{'user_preference': 0}"/>
|
||||
<field string="Companies count" name="companies_count" invisible="1"/>
|
||||
</group>
|
||||
<group string="Allowed Branches">
|
||||
<field name="default_branch_id" domain="[('company_id','=',company_id)]"/>
|
||||
<field name="branch_ids" widget="many2many_tags" domain="[('company_id','=',company_id)]"/>
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</flectra>
|
@ -3,7 +3,7 @@
|
||||
|
||||
{
|
||||
'name': 'CRM',
|
||||
'author': 'Odoo S.A',
|
||||
'author' : 'Odoo S.A',
|
||||
'version': '1.0',
|
||||
'category': 'Sales',
|
||||
'sequence': 5,
|
||||
|
@ -53,6 +53,7 @@
|
||||
<field name="priority">1</field>
|
||||
<field name="team_id" ref="sales_team.team_sales_department"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
|
||||
<field name="date_open" eval="(DateTime.today() - relativedelta(months=2)).strftime('%Y-%m-%d %H:%M')"/>
|
||||
<field name="stage_id" ref="stage_lead1"/>
|
||||
<field name="campaign_id" ref="utm.utm_campaign_email_campaign_products"/>
|
||||
@ -82,6 +83,7 @@
|
||||
<field name="country_id" ref="base.fr"/>
|
||||
<field name="city">Bordeaux</field>
|
||||
<field name="zip">33000</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
|
||||
<field name="street">Rue Ignasse Blanchoux 214/32</field>
|
||||
<field name="phone">+33 1 25 54 45 69</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [categ_oppor2])]"/>
|
||||
@ -111,6 +113,7 @@
|
||||
<field name="email_from">contact@thekompany.example.com</field>
|
||||
<field name="country_id" ref="base.us"/>
|
||||
<field name="city">New York</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
|
||||
<field name="zip">10001</field>
|
||||
<field name="street">Lafayette Ave 450/12</field>
|
||||
<field name="phone">+1 555 754 3010</field>
|
||||
@ -133,6 +136,7 @@
|
||||
<field name="email_from">hmc@yahoo.example.com</field>
|
||||
<field name="country_id" ref="base.uk"/>
|
||||
<field name="city">Manchester</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
|
||||
<field name="zip">03101</field>
|
||||
<field name="street">United Street 68</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [categ_oppor5])]"/>
|
||||
@ -369,6 +373,7 @@ Andrew</p>]]></field>
|
||||
<field name="partner_name">Rediff Mail</field>
|
||||
<field name="email_from">willmac@rediffmail.example.com</field>
|
||||
<field name="country_id" ref="base.au"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
|
||||
<field name="city">Melbourne</field>
|
||||
<field name="street">Kensington Road 189</field>
|
||||
<field name="tag_ids" eval="[(6, 0, [categ_oppor1])]"/>
|
||||
|
@ -50,7 +50,7 @@ class Lead(models.Model):
|
||||
_name = "crm.lead"
|
||||
_description = "Lead/Opportunity"
|
||||
_order = "priority desc,activity_date_deadline,id desc"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin', 'utm.mixin', 'format.address.mixin']
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin', 'utm.mixin', 'format.address.mixin', 'ir.branch.company.mixin']
|
||||
|
||||
def _default_probability(self):
|
||||
stage_id = self._default_stage_id()
|
||||
|
@ -78,6 +78,7 @@ class Team(models.Model):
|
||||
values['alias_defaults'] = defaults = safe_eval(self.alias_defaults or "{}")
|
||||
defaults['type'] = 'lead' if has_group_use_lead and self.use_leads else 'opportunity'
|
||||
defaults['team_id'] = self.id
|
||||
defaults['branch_id'] = self.branch_id and self.branch_id.id
|
||||
return values
|
||||
|
||||
@api.onchange('use_leads', 'use_opportunities')
|
||||
|
@ -84,6 +84,16 @@
|
||||
<field name="domain_force">['|',('user_id','=',user.id),('user_id','=',False)]</field>
|
||||
<field name="groups" eval="[(4, ref('sales_team.group_sale_salesman'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- Multi Branch rule -->
|
||||
<record id="crm_lead_multi_branch_rule" model="ir.rule">
|
||||
<field name="name">Lead multi-branch</field>
|
||||
<field name="model_id" ref="model_crm_lead"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('branch_id', '=', False), '|', ('branch_id', '=', user.default_branch_id.id),
|
||||
('branch_id', 'in', user.branch_ids.ids)]
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
|
||||
</flectra>
|
||||
|
@ -5,3 +5,4 @@ from . import test_new_lead_notification
|
||||
from . import test_lead2opportunity
|
||||
from . import test_crm_activity
|
||||
from . import test_crm_ui
|
||||
from . import test_crm_branch
|
||||
|
@ -33,11 +33,13 @@ class TestCrmCases(TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestCrmCases, self).setUp()
|
||||
|
||||
branch0 = self.env.ref('base_branch_company.data_branch_1')
|
||||
branch = self.env.ref('base_branch_company.data_branch_2')
|
||||
# Create a user as 'Crm Salesmanager' and added the `sales manager` group
|
||||
self.crm_salemanager = self.env['res.users'].create({
|
||||
'company_id': self.env.ref("base.main_company").id,
|
||||
'name': "Crm Sales manager",
|
||||
'name': "Crm Sales manager", 'default_branch_id': branch.id,
|
||||
'branch_ids': [(4, branch_id.id) for branch_id in [branch0, branch]],
|
||||
'login': "csm",
|
||||
'email': "crmmanager@yourcompany.com",
|
||||
'groups_id': [(6, 0, [self.ref('sales_team.group_sale_manager')])]
|
||||
@ -46,7 +48,8 @@ class TestCrmCases(TransactionCase):
|
||||
# Create a user as 'Crm Salesman' and added few groups
|
||||
self.crm_salesman = self.env['res.users'].create({
|
||||
'company_id': self.env.ref("base.main_company").id,
|
||||
'name': "Crm Salesman",
|
||||
'name': "Crm Salesman", 'default_branch_id': branch.id,
|
||||
'branch_ids': [(4, branch_id.id) for branch_id in [branch0, branch]],
|
||||
'login': "csu",
|
||||
'email': "crmuser@yourcompany.com",
|
||||
'groups_id': [(6, 0, [self.env.ref('sales_team.group_sale_salesman_all_leads').id, self.env.ref('base.group_partner_manager').id])]
|
||||
|
@ -34,10 +34,12 @@ class TestCrmMailActivity(TestCrmCases):
|
||||
|
||||
# I create an opportunity, as salesman
|
||||
self.partner_client = self.env.ref("base.res_partner_1")
|
||||
branch = self.env.ref('base_branch_company.data_branch_2')
|
||||
self.lead = self.env['crm.lead'].sudo(self.crm_salesman.id).create({
|
||||
'name': 'Test Opp',
|
||||
'type': 'opportunity',
|
||||
'partner_id': self.partner_client.id,
|
||||
'branch_id': branch.id,
|
||||
'team_id': self.env.ref("sales_team.team_sales_department").id,
|
||||
'user_id': self.crm_salesman.id,
|
||||
})
|
||||
|
68
addons/crm/tests/test_crm_branch.py
Normal file
68
addons/crm/tests/test_crm_branch.py
Normal file
@ -0,0 +1,68 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from flectra.tests import common
|
||||
|
||||
|
||||
class TestCrmBranch(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestCrmBranch, self).setUp()
|
||||
|
||||
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
|
||||
self.branch_2 = self.env.ref('base_branch_company.data_branch_2')
|
||||
self.model_crm = self.env['crm.lead']
|
||||
self.sale_user_group = self.env.ref('sales_team.group_sale_manager')
|
||||
self.main_company = self.env.ref('base.main_company')
|
||||
self.crm_user_group = self.env.ref('base.group_user')
|
||||
|
||||
self.user_1 = self.create_crm_user(self.main_company, self.branch_1, [self.branch_1],'user_1', [self.sale_user_group,
|
||||
self.crm_user_group])
|
||||
self.user_2 = self.create_crm_user(self.main_company, self.branch_2, [self.branch_2], 'user_2', [self.sale_user_group,
|
||||
self.crm_user_group])
|
||||
self.team1=self.env.ref('sales_team.team_sales_department')
|
||||
self.team1.write({'branch_id': self.branch_1.id, 'user_id': self.user_1.id})
|
||||
self.team2 = self.env.ref('sales_team.crm_team_1')
|
||||
self.team2.write({'branch_id': self.branch_2.id, 'user_id': self.user_2.id})
|
||||
|
||||
self.lead_1 = self.lead_create(self.branch_1, self.team1, self.user_1.id)
|
||||
self.lead_2 = self.lead_create(self.branch_2, self.team2, self.user_2.id)
|
||||
|
||||
def create_crm_user(self, main_company, branch, branch_ids, login_user, groups):
|
||||
groups = [group.id for group in groups]
|
||||
user_obj = self.env['res.users'].create({
|
||||
'company_id': main_company.id,
|
||||
'branch_ids': [(4, branch_id.id) for branch_id in branch_ids],
|
||||
'default_branch_id': branch.id,
|
||||
'company_ids': [(4, main_company.id)],
|
||||
'groups_id': [(6, 0, groups)],
|
||||
'login': login_user,
|
||||
'name': 'CRM Test ' + login_user,
|
||||
'email': 'demo@yourcompany.com',
|
||||
'password': '123',
|
||||
})
|
||||
return user_obj
|
||||
|
||||
|
||||
def lead_create(self, branch_id, team_id, user_id, ):
|
||||
lead_name = 'CRM LEAD '
|
||||
lead = self.model_crm.create({
|
||||
'user_id': user_id,
|
||||
'team_id': team_id.id,
|
||||
'name': lead_name + branch_id.name,
|
||||
'branch_id': branch_id.id,
|
||||
})
|
||||
return lead
|
||||
|
||||
def test_lead_authentication(self):
|
||||
lead_ids = self.model_crm.sudo(self.user_2.id).search(
|
||||
[('branch_id', '=', self.branch_1.id), ('id', '=', self.lead_1.id)])
|
||||
self.assertEqual(lead_ids.ids, [], ('%s should not have'
|
||||
' access to %s')
|
||||
% (self.user_2.name, self.branch_1.name))
|
||||
|
||||
def test_team_branch(self):
|
||||
lead = self.lead_create(self.branch_2, self.team2, self.user_2.id )
|
||||
self.assertEqual(
|
||||
lead.branch_id, self.branch_2, ('%s lead '
|
||||
'should have %s as branch')
|
||||
% (self.user_2.name,
|
||||
self.branch_2.name))
|
@ -25,8 +25,10 @@ class TestCRMLead(TestCrmCases):
|
||||
|
||||
def test_find_stage(self):
|
||||
# I create a new lead
|
||||
branch = self.env.ref('base_branch_company.data_branch_1')
|
||||
lead = self.env['crm.lead'].create({
|
||||
'type': "lead",
|
||||
'branch_id': branch.id,
|
||||
'name': "Test lead new",
|
||||
'partner_id': self.env.ref("base.res_partner_1").id,
|
||||
'description': "This is the description of the test new lead.",
|
||||
@ -77,11 +79,12 @@ class TestCRMLead(TestCrmCases):
|
||||
# During a mixed merge (involving leads and opps), data should be handled a certain way following their type (m2o, m2m, text, ...) Start by creating two leads and an opp and giving the rights of Sales manager.
|
||||
default_stage_id = self.ref("crm.stage_lead1")
|
||||
LeadSalesmanager = self.env['crm.lead'].sudo(self.crm_salemanager.id)
|
||||
|
||||
branch = self.env.ref('base_branch_company.data_branch_2')
|
||||
# TEST CASE 1
|
||||
test_crm_opp_01 = LeadSalesmanager.create({
|
||||
'type': 'opportunity',
|
||||
'name': 'Test opportunity 1',
|
||||
'branch_id': branch.id,
|
||||
'partner_id': self.env.ref("base.res_partner_3").id,
|
||||
'stage_id': default_stage_id,
|
||||
'description': 'This is the description of the test opp 1.'
|
||||
@ -91,7 +94,7 @@ class TestCRMLead(TestCrmCases):
|
||||
'type': 'lead',
|
||||
'name': 'Test lead first',
|
||||
'partner_id': self.env.ref("base.res_partner_1").id,
|
||||
'stage_id': default_stage_id,
|
||||
'stage_id': default_stage_id, 'branch_id': branch.id,
|
||||
'description': 'This is the description of the test lead first.'
|
||||
})
|
||||
|
||||
@ -99,7 +102,7 @@ class TestCRMLead(TestCrmCases):
|
||||
'type': 'lead',
|
||||
'name': 'Test lead second',
|
||||
'partner_id': self.env.ref("base.res_partner_1").id,
|
||||
'stage_id': default_stage_id,
|
||||
'stage_id': default_stage_id, 'branch_id': branch.id,
|
||||
'description': 'This is the description of the test lead second.'
|
||||
})
|
||||
|
||||
@ -124,14 +127,14 @@ class TestCRMLead(TestCrmCases):
|
||||
# I want to test leads merge. Start by creating two leads (with the same partner)
|
||||
test_crm_lead_03 = LeadSalesmanager.create({
|
||||
'type': 'lead',
|
||||
'name': 'Test lead 3',
|
||||
'name': 'Test lead 3', 'branch_id': branch.id,
|
||||
'partner_id': self.env.ref("base.res_partner_1").id,
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
|
||||
test_crm_lead_04 = LeadSalesmanager.create({
|
||||
'type': 'lead',
|
||||
'name': 'Test lead 4',
|
||||
'name': 'Test lead 4', 'branch_id': branch.id,
|
||||
'partner_id': self.env.ref("base.res_partner_1").id,
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
@ -154,14 +157,14 @@ class TestCRMLead(TestCrmCases):
|
||||
# I want to test opps merge. Start by creating two opportunities (with the same partner).
|
||||
test_crm_opp_02 = LeadSalesmanager.create({
|
||||
'type': 'opportunity',
|
||||
'name': 'Test opportunity 2',
|
||||
'name': 'Test opportunity 2', 'branch_id': branch.id,
|
||||
'partner_id': self.env.ref("base.res_partner_3").id,
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
|
||||
test_crm_opp_03 = LeadSalesmanager.create({
|
||||
'type': 'opportunity',
|
||||
'name': 'Test opportunity 3',
|
||||
'name': 'Test opportunity 3', 'branch_id': branch.id,
|
||||
'partner_id': self.env.ref("base.res_partner_3").id,
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
|
@ -38,6 +38,7 @@ class TestLead2opportunity2win(TestCrmCases):
|
||||
crm_case_3.message_post(subject='Test note', body='Détails envoyés par le client sur le FAX pour la qualité')
|
||||
|
||||
# I convert mass lead into opportunity customer.
|
||||
branch = self.env.ref('base_branch_company.data_branch_1')
|
||||
mass = CrmLead2OpportunityPartnerMass.with_context({'active_model': 'crm.lead', 'active_ids': [crm_case_13.id, crm_case_2.id], 'active_id': crm_case_13.id}).create({
|
||||
'user_ids': [(6, 0, self.env.ref('base.user_root').ids)],
|
||||
'team_id': self.env.ref("sales_team.team_sales_department").id
|
||||
@ -73,25 +74,25 @@ class TestLead2opportunity2win(TestCrmCases):
|
||||
CrmLead2OpportunityPartnerMass = self.env['crm.lead2opportunity.partner.mass']
|
||||
LeadSaleman = self.env['crm.lead'].sudo(self.crm_salesman.id)
|
||||
default_stage_id = self.ref("crm.stage_lead1")
|
||||
|
||||
branch = self.env.ref('base_branch_company.data_branch_2')
|
||||
# During a lead to opp conversion, salesmen should be assigned to leads following the round-robin method. Start by creating 4 salesmen (A to D) and 6 leads (1 to 6).
|
||||
test_res_user_01 = self.env['res.users'].create({
|
||||
'name': 'Test user A',
|
||||
'name': 'Test user A', 'default_branch_id': branch.id,
|
||||
'login': 'tua@example.com',
|
||||
'new_password': 'tua'
|
||||
})
|
||||
test_res_user_02 = self.env['res.users'].create({
|
||||
'name': 'Test user B',
|
||||
'name': 'Test user B', 'default_branch_id': branch.id,
|
||||
'login': 'tub@example.com',
|
||||
'new_password': 'tub'
|
||||
})
|
||||
test_res_user_03 = self.env['res.users'].create({
|
||||
'name': 'Test user C',
|
||||
'name': 'Test user C', 'default_branch_id': branch.id,
|
||||
'login': 'tuc@example.com',
|
||||
'new_password': 'tuc'
|
||||
})
|
||||
test_res_user_04 = self.env['res.users'].create({
|
||||
'name': 'Test user D',
|
||||
'name': 'Test user D', 'default_branch_id': branch.id,
|
||||
'login': 'tud@example.com',
|
||||
'new_password': 'tud'
|
||||
})
|
||||
@ -99,36 +100,36 @@ class TestLead2opportunity2win(TestCrmCases):
|
||||
# Salesman also creates lead so giving access rights of salesman.
|
||||
test_crm_lead_01 = LeadSaleman.create({
|
||||
'type': 'lead',
|
||||
'name': 'Test lead 1',
|
||||
'name': 'Test lead 1', 'branch_id': branch.id,
|
||||
'email_from': 'Raoul Grosbedon <raoul@grosbedon.fr>',
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
test_crm_lead_02 = LeadSaleman.create({
|
||||
'type': 'lead',
|
||||
'type': 'lead', 'branch_id': branch.id,
|
||||
'name': 'Test lead 2',
|
||||
'email_from': 'Raoul Grosbedon <raoul@grosbedon.fr>',
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
test_crm_lead_03 = LeadSaleman.create({
|
||||
'type': 'lead',
|
||||
'type': 'lead', 'branch_id': branch.id,
|
||||
'name': 'Test lead 3',
|
||||
'email_from': 'Raoul Grosbedon <raoul@grosbedon.fr>',
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
test_crm_lead_04 = LeadSaleman.create({
|
||||
'type': 'lead',
|
||||
'type': 'lead', 'branch_id': branch.id,
|
||||
'name': 'Test lead 4',
|
||||
'email_from': 'Fabrice Lepoilu',
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
test_crm_lead_05 = LeadSaleman.create({
|
||||
'type': 'lead',
|
||||
'type': 'lead', 'branch_id': branch.id,
|
||||
'name': 'Test lead 5',
|
||||
'email_from': 'Fabrice Lepoilu',
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
test_crm_lead_06 = LeadSaleman.create({
|
||||
'type': 'lead',
|
||||
'type': 'lead', 'branch_id': branch.id,
|
||||
'name': 'Test lead 6',
|
||||
'email_from': 'Agrolait SuperSeed SA',
|
||||
'stage_id': default_stage_id
|
||||
|
@ -16,6 +16,7 @@ class NewLeadNotification(TestCrm):
|
||||
|
||||
# Imitate what happens in the controller when somebody creates a new
|
||||
# lead from the website form
|
||||
branch = self.env.ref('base_branch_company.data_branch_1')
|
||||
lead = self.env["crm.lead"].with_context(mail_create_nosubscribe=True).sudo().create({
|
||||
"contact_name": "Somebody",
|
||||
"description": "Some question",
|
||||
@ -23,6 +24,7 @@ class NewLeadNotification(TestCrm):
|
||||
"name": "Some subject",
|
||||
"partner_name": "Some company",
|
||||
"team_id": self.sales_team_1.id,
|
||||
"branch_id": branch.id,
|
||||
"phone": "+0000000000"
|
||||
})
|
||||
# partner and channel should be auto subscribed
|
||||
|
@ -89,6 +89,7 @@
|
||||
<field name="user_id" domain="[('share', '=', False)]"
|
||||
context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'sales_team.group_sale_salesman_all_leads'], 'team_id': team_id}"/>
|
||||
<field name="team_id" widget="selection" domain="[('use_leads','=',True)]"/>
|
||||
<field name="branch_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
<field name="type" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
@ -492,6 +493,7 @@
|
||||
<group>
|
||||
<field name="user_id" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'sales_team.group_sale_salesman_all_leads'], 'team_id': team_id}" domain="[('share', '=', False)]"/>
|
||||
<field name="team_id" widget="selection"/>
|
||||
<field name="branch_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="priority" widget="priority"/>
|
||||
@ -650,6 +652,7 @@
|
||||
<filter string="Sales Channel" context="{'group_by':'team_id'}"/>
|
||||
<filter string="Country" context="{'group_by':'country_id'}" />
|
||||
<filter string="Company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
|
||||
<filter string="Branch" context="{'group_by':'branch_id'}"/>
|
||||
<filter name="stage" string="Stage" context="{'group_by':'stage_id'}"/>
|
||||
<filter string="Campaign" domain="[]" context="{'group_by':'campaign_id'}"/>
|
||||
<filter string="Medium" domain="[]" context="{'group_by':'medium_id'}"/>
|
||||
|
@ -8,14 +8,14 @@ from dateutil.relativedelta import relativedelta
|
||||
import json
|
||||
|
||||
from flectra import api, fields, models, _
|
||||
from flectra.exceptions import UserError
|
||||
from flectra.exceptions import UserError, ValidationError
|
||||
from flectra.release import version
|
||||
from flectra.tools import DEFAULT_SERVER_DATE_FORMAT as DF
|
||||
|
||||
|
||||
class CrmTeam(models.Model):
|
||||
_name = "crm.team"
|
||||
_inherit = ['mail.thread']
|
||||
_inherit = ['mail.thread', 'ir.branch.company.mixin']
|
||||
_description = "Sales Channel"
|
||||
_order = "name"
|
||||
|
||||
@ -81,6 +81,18 @@ class CrmTeam(models.Model):
|
||||
('year', 'Last Year'),
|
||||
], string='Scale', default='month', help="The time period this channel's dashboard graph will consider.")
|
||||
|
||||
@api.constrains('company_id', 'branch_id')
|
||||
def _check_company_branch(self):
|
||||
for record in self:
|
||||
if record.company_id and record.company_id != record.branch_id.company_id:
|
||||
raise ValidationError(
|
||||
_('Configuration Error of Company:\n'
|
||||
'The Company (%s) in the Team and '
|
||||
'the Company (%s) of Branch must '
|
||||
'be the same company!') % (record.company_id.name,
|
||||
record.branch_id.company_id.name)
|
||||
)
|
||||
|
||||
@api.depends('dashboard_graph_group', 'dashboard_graph_model', 'dashboard_graph_period')
|
||||
def _compute_dashboard_graph(self):
|
||||
for team in self.filtered('dashboard_graph_model'):
|
||||
|
@ -40,6 +40,13 @@
|
||||
<field eval="[(6,0,[ref('base.group_system')])]" name="groups_id"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.rule" id="crm_team_multi_branch_rule">
|
||||
<field name="name">CRM Team multi-branch</field>
|
||||
<field name="model_id" ref="sales_team.model_crm_team"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|',('branch_id','=', False),'|',('branch_id','=',user.default_branch_id.id), ('branch_id','in', [b.id for b in user.branch_ids])]</field>
|
||||
</record>
|
||||
|
||||
<data noupdate="1">
|
||||
<record id="base.default_user" model="res.users">
|
||||
<field name="groups_id" eval="[(4,ref('sales_team.group_sale_manager'))]"/>
|
||||
|
3
addons/sales_team/tests/__init__.py
Normal file
3
addons/sales_team/tests/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import test_branch_crm_team
|
56
addons/sales_team/tests/test_branch_crm_team.py
Normal file
56
addons/sales_team/tests/test_branch_crm_team.py
Normal file
@ -0,0 +1,56 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from flectra.tests import common
|
||||
|
||||
|
||||
class TestBranchSaleTeam(common.TransactionCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestBranchSaleTeam, self).setUp()
|
||||
|
||||
self.main_company = self.env.ref('base.main_company')
|
||||
self.sale_user_group = self.env.ref('sales_team.group_sale_manager')
|
||||
self.manager_user_group = self.env.ref('sales_team.group_sale_manager')
|
||||
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
|
||||
self.branch_3 = self.env.ref('base_branch_company.data_branch_3')
|
||||
self.user_id_1 = self.create_sale_team_user(self.main_company, 'user_1', self.branch_1,
|
||||
[self.branch_1, self.branch_3],
|
||||
[self.sale_user_group, self.manager_user_group])
|
||||
self.user_id_2 = self.create_sale_team_user(self.main_company, 'user_2', self.branch_3,
|
||||
[self.branch_3],
|
||||
[self.sale_user_group, self.manager_user_group])
|
||||
self.sales_team_1 = self.crm_team_create('CRM Team User 1', self.user_id_1, self.branch_1)
|
||||
self.sales_team_2 = self.crm_team_create('CRM Team User 2', self.user_id_2, self.branch_3)
|
||||
|
||||
def create_sale_team_user(self, main_company, user_name, branch_id, branch_ids, groups):
|
||||
group_ids = [grp.id for grp in groups]
|
||||
data = {
|
||||
'company_ids': [(4, main_company.id)],
|
||||
'branch_ids': [(4, ou.id) for ou in branch_ids],
|
||||
'company_id': main_company.id,
|
||||
'groups_id': [(6, 0, group_ids)],
|
||||
'default_branch_id': branch_id.id,
|
||||
'login': user_name,
|
||||
'name': 'Ron Sales User',
|
||||
'password': '123',
|
||||
'email': 'ron@yourcompany.com',
|
||||
}
|
||||
user_obj = self.env['res.users'].create(data)
|
||||
return user_obj
|
||||
|
||||
def crm_team_create(self, team_name, user_id, branch_id):
|
||||
crm_id = self.env['crm.team'].sudo(user_id.id).create({'name': team_name,
|
||||
'branch_id': branch_id.id})
|
||||
return crm_id
|
||||
|
||||
def get_crm_team(self, user_id, sales_team_1, branch_id):
|
||||
crm_team = self.env['crm.team'].sudo(user_id.id).search(
|
||||
[('id', '=', sales_team_1.id),
|
||||
('branch_id', '=', branch_id.id)])
|
||||
return crm_team
|
||||
|
||||
def test_user_authentication_2(self):
|
||||
crm_team = self.get_crm_team(self.user_id_1, self.sales_team_1, self.branch_3)
|
||||
self.assertEqual(crm_team.ids, [], ('%s should not have '
|
||||
'access to Branch %s') % (
|
||||
self.user_id_1.name, self.branch_1.name))
|
Loading…
Reference in New Issue
Block a user