[MERGE] base: Improve multi-company UX

TaskID: 2000277

closes odoo/odoo#33876

Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
This commit is contained in:
Robot Odoo
2019-06-04 21:40:44 +02:00
committed by GitHub
13 changed files with 46 additions and 72 deletions
@@ -8,8 +8,6 @@ class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
group_multi_company = fields.Boolean("Manage multiple companies", implied_group='base.group_multi_company')
group_toggle_company = fields.Boolean("Toggle multiple companies", implied_group='base.group_toggle_company')
company_id = fields.Many2one('res.company', string='Company', required=True,
default=lambda self: self.env.company)
user_default_rights = fields.Boolean(
@@ -117,20 +117,17 @@
</div>
</div>
</div>
<div id="multi_company">
<div id="multi_company" groups="base.group_multi_company">
<field name="company_id" invisible="1"/>
<h2>Multi-companies</h2>
<div class="row mt16 o_settings_container" name="multi_company">
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="group_multi_company"/>
</div>
<div class="o_setting_right_pane">
<label string="Multi-companies" for="group_multi_company"/>
<label string="Multi-companies" for="multi_company"/>
<div class="text-muted">
Manage multiple legal entities with separate accounting
</div>
<div class="content-group" attrs="{'invisible': [('group_multi_company','=',False)]}">
<div class="content-group">
<div class="mt16">
<button name="%(base.action_res_company_form)d" icon="fa-arrow-right" type="action" string="Companies" class="btn-link"/>
</div>
@@ -141,19 +138,7 @@
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="group_toggle_company"/>
</div>
<div class="o_setting_right_pane">
<label string="Multi-companies by Tab" for="group_toggle_company"/>
<div class="text-muted">
Manage multiple companies on the same browser tab. Be careful that this advanced tool should
only be used for reporting purpose.
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box" title="Configure company rules to automatically create SO/PO when one of your company sells/buys to another of your company." attrs="{'invisible': [('group_multi_company', '=', False)]}" id="inter_company">
<div class="col-12 col-lg-6 o_setting_box" title="Configure company rules to automatically create SO/PO when one of your company sells/buys to another of your company." id="inter_company">
<div class="o_setting_left_pane">
<field name="module_inter_company_rules" widget="upgrade_boolean"/>
</div>
+2 -7
View File
@@ -85,18 +85,13 @@ class MailController(http.Controller):
# - Guess the supposed necessary company to access the record via the method
# _get_mail_redirect_suggested_company
# - If no company, then redirect to the messaging
# - If the multi company per tag group is activated, merge the suggested company
# withe the companies on the cookie
# - else, use this company as enabled company
# - Merge the suggested company with the companies on the cookie
# - Make a new access test if it succeeds, redirect to the record. Otherwise,
# redirect to the messaging.
suggested_company = record_sudo._get_mail_redirect_suggested_company()
if not suggested_company:
raise AccessError()
if user.has_group('base.group_toggle_company'):
cids += [suggested_company.id]
else:
cids = [suggested_company.id]
cids += [suggested_company.id]
record_sudo.sudo(uid).with_context(allowed_company_ids=cids).check_access_rule('read')
except AccessError:
return cls._redirect_to_messaging()
+4
View File
@@ -164,6 +164,10 @@
<field name="user_ids" eval="[(4, ref('base.user_admin')), (4, ref('base.user_demo'))]"/>
</record>
<record id="base.group_multi_company" model="res.groups">
<field name="users" eval="[(4, ref('base.user_admin')), (4, ref('base.user_demo'))]"/>
</record>
<record id="base.main_company" model="res.company">
<field name="name">My Company (San Francisco)</field>
</record>
-1
View File
@@ -56,7 +56,6 @@ class Http(models.AbstractModel):
"web.base.url": self.env['ir.config_parameter'].sudo().get_param('web.base.url', default=''),
"show_effect": True,
"display_switch_company_menu": user.has_group('base.group_multi_company') and len(user.company_ids) > 1,
"toggle_company": user.has_group('base.group_toggle_company'),
"cache_hashes": {
"load_menus": hashlib.sha1(menu_json_utf8).hexdigest(),
"qweb": qweb_checksum,
@@ -31,7 +31,6 @@ var SwitchCompanyMenu = Widget.extend({
this._onSwitchCompanyClick = _.debounce(this._onSwitchCompanyClick, 1500, true);
this.allowed_company_ids = String(session.user_context.allowed_company_ids).split(',');
this.user_companies = session.user_companies.allowed_companies;
this.toggle_company = session.toggle_company;
var hash = $.bbq.getState()
if (!hash.cids || hash.cids === undefined) {
@@ -52,16 +51,21 @@ var SwitchCompanyMenu = Widget.extend({
* @param {MouseEvent} ev
*/
_onSwitchCompanyClick: function (ev) {
ev.preventDefault();
var companyID = $(ev.currentTarget).parent().data('company-id');
ev.stopPropagation();
var dropdownItem = $(ev.currentTarget).parent()
var dropdownMenu = dropdownItem.parent()
var companyID = dropdownItem.data('company-id');
var hash = $.bbq.getState()
var allowed_company_ids = _.map(hash.cids.split(','), function(company_id) {return parseInt(company_id);});
if ($($(ev.currentTarget).parent()).find('.fa-square-o').length) {
if (dropdownItem.find('.fa-square-o').length) {
// 1 enabled company: Stay in single company mode
if (this.allowed_company_ids.length === 1) {
allowed_company_ids = [companyID]
dropdownMenu.find('.fa-check-square').removeClass('fa-check-square').addClass('fa-square-o');
dropdownItem.find('.fa-square-o').removeClass('fa-square-o').addClass('fa-check-square');
allowed_company_ids = [companyID]
} else { // Multi company mode
allowed_company_ids.push(companyID);
dropdownItem.find('.fa-square-o').removeClass('fa-square-o').addClass('fa-check-square');
}
}
session.setCompanies(companyID, allowed_company_ids);
@@ -76,14 +80,19 @@ var SwitchCompanyMenu = Widget.extend({
* @param {MouseEvent} ev
*/
_onToggleCompanyClick: function (ev) {
var companyID = $(ev.currentTarget).parent().data('company-id');
ev.stopPropagation();
var dropdownItem = $(ev.currentTarget).parent()
var dropdownMenu = dropdownItem.parent()
var companyID = dropdownItem.data('company-id');
var hash = $.bbq.getState()
var allowed_company_ids = _.map(hash.cids.split(','), function(company_id) {return parseInt(company_id);});
var current_company_id = allowed_company_ids[0];
if ($(ev.currentTarget).find('.fa-square-o').length) {
if (dropdownItem.find('.fa-square-o').length) {
allowed_company_ids.push(companyID);
dropdownItem.find('.fa-square-o').removeClass('fa-square-o').addClass('fa-check-square');
} else {
allowed_company_ids.splice(allowed_company_ids.indexOf(companyID), 1);
dropdownItem.find('.fa-check-square').addClass('fa-square-o').removeClass('fa-check-square');
}
session.setCompanies(current_company_id, allowed_company_ids);
},
+10 -12
View File
@@ -1570,6 +1570,16 @@
</t>
<t t-foreach="widget.user_companies" t-as="company">
<div role="menuitem" href="#" class="dropdown-item d-flex py-0 px-0" data-menu="company" t-att-data-company-id="company[0]">
<div class="ml-auto pl-3 pr-3 border border-top-0 border-left-0 border-bottom-0 toggle_company o_py">
<span style="height: 2rem;">
<t t-if="widget.allowed_company_ids.includes(company[0].toString())">
<i class="fa fa-fw fa-check-square pt-2"></i>
</t>
<t t-if="!widget.allowed_company_ids.includes(company[0].toString())">
<i class="fa fa-fw fa-square-o pt-2"></i>
</t>
</span>
</div>
<div class="d-flex flex-grow-1 align-items-center py-0 log_into pl-3 o_py" t-att-style="company[0] === widget.current_company ? 'background-color: lightgrey;' : ''">
<t t-if="widget.allowed_company_ids.includes(company[0].toString())">
<span class='mr-3 company_label'>
@@ -1582,18 +1592,6 @@
</span>
</t>
</div>
<t t-if="widget.toggle_company">
<div class="ml-auto pl-3 pr-3 border border-top-0 border-right-0 border-bottom-0 toggle_company o_py">
<span style="height: 2rem;">
<t t-if="widget.allowed_company_ids.includes(company[0].toString())">
<i class="fa fa-fw fa-check-square pt-2"></i>
</t>
<t t-if="!widget.allowed_company_ids.includes(company[0].toString())">
<i class="fa fa-fw fa-square-o pt-2"></i>
</t>
</span>
</div>
</t>
</div>
</t>
</div>
-1
View File
@@ -80,7 +80,6 @@ The kernel of Odoo, needed for all installation.
'data/res_bank_demo.xml',
'data/res_partner_demo.xml',
'data/res_partner_image_demo.xml',
'data/res_groups_demo.xml',
],
'test': [],
'installable': True,
@@ -110,9 +110,5 @@
<field name="category_id" ref="module_category_usability"/>
</record>
<record id="group_toggle_company" model="res.groups">
<field name="category_id" ref="module_category_hidden"/>
</record>
</data>
</odoo>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="group_toggle_company" model="res.groups">
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
</record>
</data>
</odoo>
+9 -6
View File
@@ -43,20 +43,23 @@ class Company(models.Model):
with tools.file_open(img_path, 'rb') as f:
if original:
return base64.b64encode(f.read())
# Modify the source image to change the color of the 'O'.
# Modify the source image to add a colored bar on the bottom
# This could seem overkill to modify the pixels 1 by 1, but
# Pillow doesn't provide an easy way to do it, and this
# is acceptable for a 16x16 image.
color = (randrange(32, 224, 24), randrange(32, 224, 24), randrange(32, 224, 24))
original = Image.open(f)
new_image = Image.new('RGBA', original.size)
for y in range(original.size[1]):
for x in range(original.size[0]):
height = original.size[1]
width = original.size[0]
bar_size = 1
for y in range(height):
for x in range(width):
pixel = original.getpixel((x, y))
if pixel[0] == 0 and pixel[1] == 0 and pixel[2] == 0:
new_image.putpixel((x, y), (0, 0, 0, 0))
if height - bar_size <= y + 1 <= height:
new_image.putpixel((x, y), (color[0], color[1], color[2], 255))
else:
new_image.putpixel((x, y), (color[0], color[1], color[2], pixel[3]))
new_image.putpixel((x, y), (pixel[0], pixel[1], pixel[2], pixel[3]))
stream = io.BytesIO()
new_image.save(stream, format="ICO")
return base64.b64encode(stream.getvalue())
@@ -41,10 +41,6 @@
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
</record>
<record id="group_toggle_company" model="res.groups">
<field name="name">Allow to toggle company visibility in the company switch bar</field>
</record>
<record model="res.groups" id="group_partner_manager">
<field name="name">Contact Creation</field>
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
+1 -1
View File
@@ -38,7 +38,7 @@
<field name="currency_id" options="{'no_create': True, 'no_open': True}" id="company_currency" context="{'active_test': False}"/>
<field name="parent_id" groups="base.group_multi_company"/>
<field name="sequence" invisible="1"/>
<field name="favicon" widget="image" class="float-left oe_avatar"/>
<field name="favicon" widget="image" class="float-left oe_avatar" groups="base.group_no_one"/>
</group>
<group name="social_media"/>
</group>