diff --git a/addons/hr/views/res_users.xml b/addons/hr/views/res_users.xml
index c5724bd8fc1..17c7f58cd1e 100644
--- a/addons/hr/views/res_users.xml
+++ b/addons/hr/views/res_users.xml
@@ -16,12 +16,6 @@
-
-
-
-
-
-
1
diff --git a/addons/sale_stock/__manifest__.py b/addons/sale_stock/__manifest__.py
index e685e966c69..0992ac081e0 100644
--- a/addons/sale_stock/__manifest__.py
+++ b/addons/sale_stock/__manifest__.py
@@ -29,6 +29,7 @@ Preferences
'views/sale_stock_portal_template.xml',
'views/stock_production_lot_views.xml',
'views/report_invoice.xml',
+ 'views/res_users_views.xml',
'report/sale_order_report_templates.xml',
'report/stock_report_deliveryslip.xml',
'data/sale_stock_data.xml',
diff --git a/addons/sale_stock/models/__init__.py b/addons/sale_stock/models/__init__.py
index b2be36f44b9..e2983e92c78 100644
--- a/addons/sale_stock/models/__init__.py
+++ b/addons/sale_stock/models/__init__.py
@@ -7,3 +7,4 @@ from . import sale_order
from . import res_config_settings
from . import stock
from . import product_template
+from . import res_users
diff --git a/addons/sale_stock/models/res_users.py b/addons/sale_stock/models/res_users.py
new file mode 100644
index 00000000000..053fee222da
--- /dev/null
+++ b/addons/sale_stock/models/res_users.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, fields
+
+
+class Users(models.Model):
+ _inherit = ['res.users']
+
+ property_warehouse_id = fields.Many2one('stock.warehouse', string='Default Warehouse', company_dependent=True, check_company=True)
+
+ def _get_default_warehouse_id(self):
+ if self.property_warehouse_id:
+ return self.property_warehouse_id
+ return self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
+
+ def __init__(self, pool, cr):
+ """ Override of __init__ to add access rights.
+ Access rights are disabled by default, but allowed
+ on some specific fields defined in self.SELF_{READ/WRITE}ABLE_FIELDS.
+ """
+
+ sale_stock_writeable_fields = [
+ 'property_warehouse_id',
+ ]
+
+ init_res = super().__init__(pool, cr)
+ # duplicate list to avoid modifying the original reference
+ type(self).SELF_READABLE_FIELDS = type(self).SELF_READABLE_FIELDS + sale_stock_writeable_fields
+ type(self).SELF_WRITEABLE_FIELDS = type(self).SELF_WRITEABLE_FIELDS + sale_stock_writeable_fields
+ return init_res
diff --git a/addons/sale_stock/models/sale_order.py b/addons/sale_stock/models/sale_order.py
index 59234024ceb..2fef194d436 100644
--- a/addons/sale_stock/models/sale_order.py
+++ b/addons/sale_stock/models/sale_order.py
@@ -15,9 +15,7 @@ class SaleOrder(models.Model):
@api.model
def _default_warehouse_id(self):
- company = self.env.company.id
- warehouse_ids = self.env['stock.warehouse'].search([('company_id', '=', company)], limit=1)
- return warehouse_ids
+ return self.user_id._get_default_warehouse_id()
incoterm = fields.Many2one(
'account.incoterms', 'Incoterm',
@@ -66,9 +64,10 @@ class SaleOrder(models.Model):
@api.model
def create(self, vals):
- if 'warehouse_id' not in vals and 'company_id' in vals and vals.get('company_id') != self.env.company.id:
- vals['warehouse_id'] = self.env['stock.warehouse'].search([('company_id', '=', vals.get('company_id'))], limit=1).id
- return super(SaleOrder, self).create(vals)
+ if 'warehouse_id' not in vals and 'company_id' in vals:
+ user = self.env['res.users'].browse(vals.get('user_id', False))
+ vals['warehouse_id'] = user.with_company(vals.get('company_id'))._get_default_warehouse_id().id
+ return super().create(vals)
def write(self, values):
if values.get('order_line') and self.state == 'sale':
@@ -123,7 +122,12 @@ class SaleOrder(models.Model):
@api.onchange('company_id')
def _onchange_company_id(self):
if self.company_id:
- self.warehouse_id = self.env['stock.warehouse'].search([('company_id', '=', self.company_id.id)], limit=1)
+ self.warehouse_id = self.user_id.with_company(self.company_id.id)._get_default_warehouse_id().id
+
+ @api.onchange('user_id')
+ def onchange_user_id(self):
+ super().onchange_user_id()
+ self.warehouse_id = self.user_id.with_company(self.company_id.id)._get_default_warehouse_id().id
@api.onchange('partner_shipping_id')
def _onchange_partner_shipping_id(self):
diff --git a/addons/sale_stock/tests/__init__.py b/addons/sale_stock/tests/__init__.py
index 43ad813d2c3..c9c90165757 100644
--- a/addons/sale_stock/tests/__init__.py
+++ b/addons/sale_stock/tests/__init__.py
@@ -6,3 +6,4 @@ from . import test_anglo_saxon_valuation_reconciliation
from . import test_sale_stock
from . import test_sale_stock_lead_time
from . import test_sale_order_dates
+from . import test_sale_stock_multicompany
diff --git a/addons/sale_stock/tests/test_sale_stock_multicompany.py b/addons/sale_stock/tests/test_sale_stock_multicompany.py
new file mode 100644
index 00000000000..307dc23a6e9
--- /dev/null
+++ b/addons/sale_stock/tests/test_sale_stock_multicompany.py
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from datetime import datetime, timedelta
+
+from odoo.addons.sale.tests.test_sale_common import TestSaleCommon
+from odoo.tests import tagged
+from odoo.tests.common import new_test_user
+
+
+@tagged('post_install', '-at_install')
+class TestSaleStockMultiCompany(TestSaleCommon):
+
+ @classmethod
+ def setUpClass(cls):
+ super().setUpClass()
+ cls.company_B = cls.env['res.company'].create({'name': 'Company B'})
+ cls.warehouse_A = cls.env['stock.warehouse'].create({'name': 'WH A', 'code': 'WHA', 'company_id': cls.env.company.id, 'partner_id': cls.env.company.partner_id.id})
+ cls.warehouse_A2 = cls.env['stock.warehouse'].create({'name': 'WH A 2', 'code': 'WHA2', 'company_id': cls.env.company.id, 'partner_id': cls.env.company.partner_id.id, 'sequence': 5})
+ cls.warehouse_B = cls.env['stock.warehouse'].create({'name': 'WH B', 'code': 'WHB', 'company_id': cls.company_B.id, 'partner_id': cls.company_B.partner_id.id})
+ cls.warehouse_user = new_test_user(cls.env, 'WarehouseUser', groups='base.group_user,stock.group_stock_user,stock.group_stock_multi_locations,sales_team.group_sale_salesman', company_ids=[(6, 0, (cls.env.company | cls.company_B).ids)])
+ cls.warehouse_user.with_company(cls.env.company).property_warehouse_id = cls.warehouse_A.id
+ cls.warehouse_user.with_company(cls.company_B).property_warehouse_id = cls.warehouse_B.id
+
+ def test_warehouse_definition_on_so(self):
+
+ partner = self.partner
+ product = self.products['prod_del']
+
+ sale_order_vals = {
+ 'partner_id': partner.id,
+ 'partner_invoice_id': partner.id,
+ 'partner_shipping_id': partner.id,
+ 'user_id': False,
+ 'company_id': self.env.company.id,
+ 'order_line': [(0, 0, {
+ 'name': product.name,
+ 'product_id': product.id,
+ 'product_uom_qty': 10,
+ 'product_uom': product.uom_id.id,
+ 'price_unit': product.list_price})],
+ 'pricelist_id': self.env.ref('product.list0').id,
+ }
+ sale_order = self.env['sale.order']
+
+ so_no_user = sale_order.create(sale_order_vals)
+ self.assertFalse(so_no_user.user_id.property_warehouse_id)
+ self.assertEqual(so_no_user.warehouse_id.id, self.warehouse_A2.id)
+
+ sale_order_vals2 = {
+ 'partner_id': partner.id,
+ 'partner_invoice_id': partner.id,
+ 'partner_shipping_id': partner.id,
+ 'user_id': self.warehouse_user.id,
+ 'company_id': self.env.company.id,
+ 'order_line': [(0, 0, {
+ 'name': product.name,
+ 'product_id': product.id,
+ 'product_uom_qty': 10,
+ 'product_uom': product.uom_id.id,
+ 'price_unit': product.list_price})],
+ 'pricelist_id': self.env.ref('product.list0').id,
+ }
+ so_company_A = sale_order.with_company(self.env.company).create(sale_order_vals2)
+ self.assertEqual(so_company_A.warehouse_id.id, self.warehouse_A.id)
+
+ sale_order_vals3 = {
+ 'partner_id': partner.id,
+ 'partner_invoice_id': partner.id,
+ 'partner_shipping_id': partner.id,
+ 'user_id': self.warehouse_user.id,
+ 'company_id': self.company_B.id,
+ 'order_line': [(0, 0, {
+ 'name': product.name,
+ 'product_id': product.id,
+ 'product_uom_qty': 10,
+ 'product_uom': product.uom_id.id,
+ 'price_unit': product.list_price})],
+ 'pricelist_id': self.env.ref('product.list0').id,
+ }
+ so_company_B = sale_order.with_company(self.company_B).create(sale_order_vals3)
+ self.assertEqual(so_company_B.warehouse_id.id, self.warehouse_B.id)
diff --git a/addons/sale_stock/views/res_users_views.xml b/addons/sale_stock/views/res_users_views.xml
new file mode 100644
index 00000000000..d141c4ea7e0
--- /dev/null
+++ b/addons/sale_stock/views/res_users_views.xml
@@ -0,0 +1,44 @@
+
+
+
+
+ res.users.preferences.form.inherit
+ res.users
+
+
+
+
+
+
+
+
+
+
+
+ res.users.simple.form.inherit
+ res.users
+
+
+
+
+
+
+
+
+
+
+
+ res.users.form.inherit
+ res.users
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/addons/sale_timesheet/wizard/project_create_sale_order.py b/addons/sale_timesheet/wizard/project_create_sale_order.py
index 9a91e329fc7..7b6029e8296 100644
--- a/addons/sale_timesheet/wizard/project_create_sale_order.py
+++ b/addons/sale_timesheet/wizard/project_create_sale_order.py
@@ -94,6 +94,9 @@ class ProjectCreateSalesOrder(models.TransientModel):
})
sale_order.onchange_partner_id()
sale_order.onchange_partner_shipping_id()
+ # rewrite the user as the onchange_partner_id erases it
+ sale_order.write({'user_id': self.project_id.user_id.id})
+ sale_order.onchange_user_id()
# create the sale lines, the map (optional), and assign existing timesheet to sale lines
self._make_billable(sale_order)
diff --git a/addons/sale_timesheet/wizard/project_task_create_sale_order.py b/addons/sale_timesheet/wizard/project_task_create_sale_order.py
index 27d9213268d..e697f95592c 100644
--- a/addons/sale_timesheet/wizard/project_task_create_sale_order.py
+++ b/addons/sale_timesheet/wizard/project_task_create_sale_order.py
@@ -67,6 +67,9 @@ class ProjectTaskCreateSalesOrder(models.TransientModel):
})
sale_order.onchange_partner_id()
sale_order.onchange_partner_shipping_id()
+ # rewrite the user as the onchange_partner_id erases it
+ sale_order.write({'user_id': self.task_id.user_id.id})
+ sale_order.onchange_user_id()
sale_order_line = self.env['sale.order.line'].create({
'order_id': sale_order.id,
diff --git a/odoo/addons/base/views/res_users_views.xml b/odoo/addons/base/views/res_users_views.xml
index bc08c1ec562..f3b24835761 100644
--- a/odoo/addons/base/views/res_users_views.xml
+++ b/odoo/addons/base/views/res_users_views.xml
@@ -137,7 +137,7 @@
-
+