[IMP] delivery, product, sale(_management): make company consistence

Purpose of the commit is to make the multi company consistence with product,
sale order and order template.

So the Common Product Catalog setting is removed from generel settings
because its behavior wasn't really clean from a technical point of view
(disabling the rule on products access) and wouldn't work as well with
new multi-company logic.
The default logic of sharing products will be kept, but when someone
wants to limit products sharing, he will do so product by product, by
setting the company_id.

Also the default company_id on product will be blank so default product
will be a sharable by multi company.
and added company_id on sale templates so user can select his/her own
company or the templates which are common.

task-2025168
Closes: #34342
This commit is contained in:
Hetashree Chauhan
2019-07-22 05:17:00 +00:00
parent a26a010324
commit 421b9dfe21
15 changed files with 56 additions and 49 deletions
-1
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import res_config_settings
from . import delivery_carrier
from . import delivery_grid
from . import product_packaging
@@ -1,13 +0,0 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
def set_values(self):
super(ResConfigSettings, self).set_values()
rule = self.env.ref('delivery.delivery_carrier_comp_rule', False)
if rule:
rule.write({'active': not bool(self.company_share_product)})
@@ -6,7 +6,6 @@
<field name="model_id" ref="model_delivery_carrier"/>
<field name="global" eval="True"/>
<field name="domain_force"> ['|', ('company_id', 'in', company_ids), ('company_id', '=', False)]</field>
<field name="active" eval="False"/>
</record>
</data>
</odoo>
+1 -2
View File
@@ -107,8 +107,7 @@ class ProductTemplate(models.Model):
default=_get_default_uom_id, required=True,
help="Default unit of measure used for purchase orders. It must be in the same category as the default unit of measure.")
company_id = fields.Many2one(
'res.company', 'Company',
default=lambda self: self.env.company, index=1)
'res.company', 'Company', index=1)
packaging_ids = fields.One2many(
'product.packaging', string="Product Packages", compute="_compute_packaging_ids", inverse="_set_packaging_ids",
help="Gives the different ways to package the same product.")
@@ -7,11 +7,6 @@ from odoo import api, fields, models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
company_share_product = fields.Boolean(
'Share product to all companies',
help="Share your product to all companies defined in your instance.\n"
" * Checked : Product are visible for every company, even if a company is defined on the partner.\n"
" * Unchecked : Each company can see only its product (product where company is defined). Product not related to a company are visible for all companies.")
group_uom = fields.Boolean("Units of Measure", implied_group='uom.group_uom')
group_product_variant = fields.Boolean("Variants", implied_group='product.group_product_variant')
module_sale_product_configurator = fields.Boolean("Product Configurator")
@@ -47,17 +42,3 @@ class ResConfigSettings(models.TransientModel):
If the user enables the product configurator -> enable the product variants as well"""
if self.module_sale_product_configurator and not self.group_product_variant:
self.group_product_variant = True
@api.model
def get_values(self):
res = super(ResConfigSettings, self).get_values()
product_rule = self.env.ref('product.product_comp_rule')
res.update(
company_share_product=not bool(product_rule.active),
)
return res
def set_values(self):
super(ResConfigSettings, self).set_values()
product_rule = self.env.ref('product.product_comp_rule')
product_rule.write({'active': not bool(self.company_share_product)})
@@ -35,7 +35,6 @@
<field name="model_id" ref="model_product_template"/>
<field name="global" eval="True"/>
<field name="domain_force"> ['|', ('company_id', 'in', company_ids), ('company_id', '=', False)]</field>
<field name="active" eval="False"/>
</record>
<record model="ir.rule" id="product_pricelist_comp_rule">
@@ -5,10 +5,6 @@
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='company_share_partner']" position="after">
<field name="company_share_product" class="oe_inline"/>
<label string="Common Product Catalog" class="o_light_label" for="company_share_product"/>
</xpath>
<xpath expr="//div[@id='multi_company']" position="before">
<h2>Products</h2>
<div class="row mt16 o_settings_container" id="product_general_settings">
+8
View File
@@ -200,6 +200,14 @@ class SaleOrder(models.Model):
('confirmation_date_conditional_required', "CHECK( (state IN ('sale', 'done') AND confirmation_date IS NOT NULL) OR state NOT IN ('sale', 'done') )", "A confirmed sales order requires a confirmation date."),
]
@api.constrains('company_id', 'order_line')
def _check_order_line_company_id(self):
for order in self:
companies = order.order_line.product_id.company_id
if companies and companies != order.company_id:
bad_products = order.order_line.product_id.filtered(lambda p: p.company_id and p.company_id != order.company_id)
raise ValidationError((_("Your quotation contains products from company %s whereas your quotation belongs to company %s. \n Please change the company of your quotation or remove the products from other companies (%s).") % (', '.join(companies.mapped('display_name')), order.company_id.display_name, ', '.join(bad_products.mapped('display_name')))))
@api.depends('pricelist_id', 'date_order', 'company_id')
def _compute_currency_rate(self):
for order in self:
+3 -2
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.exceptions import AccessError, UserError
from odoo.exceptions import AccessError, UserError, ValidationError
from odoo.tests import tagged
from .test_sale_common import TestCommonSaleNoChart
@@ -103,7 +103,8 @@ class TestAccessRights(TestCommonSaleNoChart):
# Salesperson can change a Sales Team of SO
self.order.with_user(self.user_salesperson_1).write({'team_id': self.sales_channel.id})
# Salesperson can't create the SO of other salesperson
with self.assertRaises(AccessError):
# raise ValidationError instead of AccessError due to constraint
with self.assertRaises(ValidationError):
self.env['sale.order'].with_user(self.user_salesperson_1).create({
'partner_id': self.partner_customer_usd.id,
'user_id': self.user_salesperson.id
+3
View File
@@ -313,6 +313,7 @@
<group attrs="{'invisible': [('display_type', '!=', False)]}">
<field name="product_updatable" invisible="1"/>
<field name="product_id"
domain="[('sale_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom, 'company_id': parent.company_id}"
attrs="{
'readonly': [('product_updatable', '=', False)],
@@ -417,6 +418,7 @@
'default_lst_price': price_unit,
'default_description_sale': name
}"
domain="[('sale_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"
widget="product_configurator"
/>
<field name="product_template_id"
@@ -436,6 +438,7 @@
'default_lst_price': price_unit,
'default_description_sale': name
}"
domain="[('sale_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"
widget="product_configurator"/>
<field name="name" widget="section_and_note_text" optional="show"/>
<field
+11 -2
View File
@@ -4,7 +4,7 @@
from datetime import datetime, timedelta
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.exceptions import UserError, ValidationError
class SaleOrder(models.Model):
@@ -13,12 +13,21 @@ class SaleOrder(models.Model):
sale_order_template_id = fields.Many2one(
'sale.order.template', 'Quotation Template',
readonly=True,
states={'draft': [('readonly', False)], 'sent': [('readonly', False)]})
states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
sale_order_option_ids = fields.One2many(
'sale.order.option', 'order_id', 'Optional Products Lines',
copy=True, readonly=True,
states={'draft': [('readonly', False)], 'sent': [('readonly', False)]})
@api.constrains('company_id', 'sale_order_option_ids')
def _check_optional_product_company_id(self):
for order in self:
companies = order.sale_order_option_ids.product_id.company_id
if companies and companies != order.company_id:
bad_products = order.sale_order_option_ids.product_id.filtered(lambda p: p.company_id and p.company_id != order.company_id)
raise ValidationError((_("Your quotation contains products from company %s whereas your quotation belongs to company %s. \n Please change the company of your quotation or remove the products from other companies (%s).") % (', '.join(companies.mapped('display_name')), order.company_id.display_name, ', '.join(bad_products.mapped('display_name')))))
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
if self.sale_order_template_id and self.sale_order_template_id.number_of_days > 0:
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models
from odoo.exceptions import UserError
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
class SaleOrderTemplate(models.Model):
@@ -28,6 +28,22 @@ class SaleOrderTemplate(models.Model):
domain=[('model', '=', 'sale.order')],
help="This e-mail template will be sent on confirmation. Leave empty to send nothing.")
active = fields.Boolean(default=True, help="If unchecked, it will allow you to hide the quotation template without removing it.")
company_id = fields.Many2one('res.company', string='Company')
@api.constrains('company_id', 'sale_order_template_line_ids', 'sale_order_template_option_ids')
def _check_company_id(self):
for template in self:
companies = template.mapped('sale_order_template_line_ids.product_id.company_id') | template.mapped('sale_order_template_option_ids.product_id.company_id')
if len(companies) > 1:
raise ValidationError(_("Your template cannot contain products from multiple companies."))
elif companies and companies != template.company_id:
raise ValidationError((_("Your template contains products from company %s whereas your template belongs to company %s. \n Please change the company of your template or remove the products from other companies.") % (companies.mapped('display_name'), template.company_id.display_name)))
@api.onchange('sale_order_template_line_ids', 'sale_order_template_option_ids')
def _onchange_template_line_ids(self):
companies = self.mapped('sale_order_template_option_ids.product_id.company_id') | self.mapped('sale_order_template_line_ids.product_id.company_id')
if companies and self.company_id not in companies:
self.company_id = companies[0]
def write(self, vals):
if 'active' in vals and not vals.get('active'):
@@ -6,4 +6,11 @@
<field name="category_id" ref="base.module_category_hidden"/>
</record>
<record id="sale_order_template_rule_company" model="ir.rule">
<field name="name">Quotation Template multi-company</field>
<field name="model_id" ref="model_sale_order_template"/>
<field name="global" eval="True"/>
<field name="domain_force">['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]</field>
</record>
</odoo>
@@ -33,6 +33,9 @@
<field name="number_of_days" class="oe_inline"/> days
</div>
</group>
<group>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
</group>
</group>
<notebook name="main_book">
<page string="Lines">
@@ -11,7 +11,7 @@
<field name="sale_order_option_ids" mode="tree,form,kanban">
<form string="Optional Products">
<group>
<field name="product_id"/>
<field name="product_id" domain="[('sale_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"/>
<field name="name"/>
<field name="quantity"/>
<field name="uom_id" groups="uom.group_uom"/>
@@ -67,7 +67,7 @@
<create name="add_product_control" string="Add a product"/>
</control>
<field name="sequence" widget="handle"/>
<field name="product_id"/>
<field name="product_id" domain="[('sale_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"/>
<field name="name" optional="show"/>
<field name="quantity"/>
<field name="uom_id" string="UoM" groups="uom.group_uom" optional="show"/>