diff options
| author | Hetashree Chauhan <hch@odoo.com> | 2019-06-25 06:41:16 +0000 |
|---|---|---|
| committer | Hetashree Chauhan <hch@odoo.com> | 2019-07-22 05:17:00 +0000 |
| commit | 421b9dfe211ac1a71b35f150768cbc90fb55efb7 (patch) | |
| tree | 401829e5d72ae2b68fd490f73ef4e3bf890ab88e | |
| parent | a26a010324e0cdc743c2b69c9d4100b048df7240 (diff) | |
[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
| -rw-r--r-- | addons/delivery/models/__init__.py | 1 | ||||
| -rw-r--r-- | addons/delivery/models/res_config_settings.py | 13 | ||||
| -rw-r--r-- | addons/delivery/security/delivery_carrier_security.xml | 1 | ||||
| -rw-r--r-- | addons/product/models/product_template.py | 3 | ||||
| -rw-r--r-- | addons/product/models/res_config_settings.py | 19 | ||||
| -rw-r--r-- | addons/product/security/product_security.xml | 1 | ||||
| -rw-r--r-- | addons/product/views/res_config_settings_views.xml | 4 | ||||
| -rw-r--r-- | addons/sale/models/sale.py | 8 | ||||
| -rw-r--r-- | addons/sale/tests/test_access_rights.py | 5 | ||||
| -rw-r--r-- | addons/sale/views/sale_views.xml | 3 | ||||
| -rw-r--r-- | addons/sale_management/models/sale_order.py | 13 | ||||
| -rw-r--r-- | addons/sale_management/models/sale_order_template.py | 20 | ||||
| -rw-r--r-- | addons/sale_management/security/sale_management_security.xml | 7 | ||||
| -rw-r--r-- | addons/sale_management/views/sale_order_template_views.xml | 3 | ||||
| -rw-r--r-- | addons/sale_management/views/sale_order_views.xml | 4 |
15 files changed, 56 insertions, 49 deletions
diff --git a/addons/delivery/models/__init__.py b/addons/delivery/models/__init__.py index ce55845c421..72fc7b3a04b 100644 --- a/addons/delivery/models/__init__.py +++ b/addons/delivery/models/__init__.py @@ -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 diff --git a/addons/delivery/models/res_config_settings.py b/addons/delivery/models/res_config_settings.py deleted file mode 100644 index 070f8dcdb29..00000000000 --- a/addons/delivery/models/res_config_settings.py +++ /dev/null @@ -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)}) diff --git a/addons/delivery/security/delivery_carrier_security.xml b/addons/delivery/security/delivery_carrier_security.xml index e9e22c47088..4f60ee6d286 100644 --- a/addons/delivery/security/delivery_carrier_security.xml +++ b/addons/delivery/security/delivery_carrier_security.xml @@ -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> diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index 10d87c9c623..2a55e3fc9cc 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -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.") diff --git a/addons/product/models/res_config_settings.py b/addons/product/models/res_config_settings.py index 03fb56aa1f7..f1c0c189ef1 100644 --- a/addons/product/models/res_config_settings.py +++ b/addons/product/models/res_config_settings.py @@ -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)}) diff --git a/addons/product/security/product_security.xml b/addons/product/security/product_security.xml index 4ef8ea822d0..3ee6d0294a2 100644 --- a/addons/product/security/product_security.xml +++ b/addons/product/security/product_security.xml @@ -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"> diff --git a/addons/product/views/res_config_settings_views.xml b/addons/product/views/res_config_settings_views.xml index d56daf515d7..5852e218c5a 100644 --- a/addons/product/views/res_config_settings_views.xml +++ b/addons/product/views/res_config_settings_views.xml @@ -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"> diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index 598f457b8bb..cc39e0b881a 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -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: diff --git a/addons/sale/tests/test_access_rights.py b/addons/sale/tests/test_access_rights.py index 7bf99f104cd..98aec26b9cc 100644 --- a/addons/sale/tests/test_access_rights.py +++ b/addons/sale/tests/test_access_rights.py @@ -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 diff --git a/addons/sale/views/sale_views.xml b/addons/sale/views/sale_views.xml index 1efb27f088c..541855846b4 100644 --- a/addons/sale/views/sale_views.xml +++ b/addons/sale/views/sale_views.xml @@ -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 diff --git a/addons/sale_management/models/sale_order.py b/addons/sale_management/models/sale_order.py index 19df930f19e..ef6b61d98bd 100644 --- a/addons/sale_management/models/sale_order.py +++ b/addons/sale_management/models/sale_order.py @@ -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: diff --git a/addons/sale_management/models/sale_order_template.py b/addons/sale_management/models/sale_order_template.py index 8e3dc818ef4..ee21cbce5d6 100644 --- a/addons/sale_management/models/sale_order_template.py +++ b/addons/sale_management/models/sale_order_template.py @@ -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'): diff --git a/addons/sale_management/security/sale_management_security.xml b/addons/sale_management/security/sale_management_security.xml index 0d838862462..2ec489b6650 100644 --- a/addons/sale_management/security/sale_management_security.xml +++ b/addons/sale_management/security/sale_management_security.xml @@ -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> diff --git a/addons/sale_management/views/sale_order_template_views.xml b/addons/sale_management/views/sale_order_template_views.xml index 73c79688c53..16b282899cc 100644 --- a/addons/sale_management/views/sale_order_template_views.xml +++ b/addons/sale_management/views/sale_order_template_views.xml @@ -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"> diff --git a/addons/sale_management/views/sale_order_views.xml b/addons/sale_management/views/sale_order_views.xml index e4e78db4a1b..94d5c1ca2c1 100644 --- a/addons/sale_management/views/sale_order_views.xml +++ b/addons/sale_management/views/sale_order_views.xml @@ -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"/> |
