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 @@