summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOdoo's Mergebot <xmo+roboto@odoo.com>2020-02-05 17:00:16 +0100
committerGitHub <noreply@github.com>2020-02-05 17:00:16 +0100
commite753bb1a85bac83b0e4dc536ae6d4992cbe4907f (patch)
tree28816b1b06cb56a020c9a5b59a4da3b28976e8d6
parent90053ca72f6cf17b21507fc5df42dd1577e157d1 (diff)
parenta0aac8a50ac42a72c72b2f0f208278be8cde1a60 (diff)
[MERGE] sale_stock : add a default warehouse on the user
Purpose ====== Our current integration between FSM and Stock works well for basic flows, but quickly shows limitations. We don't handle warehouse by employee. Use-case: each worker has a dedicated van with a dedicated stock. I want to track the material used for each intervention to make sure that nothing is stolen. + This is also useful in usecases outside of FSM. Example: I have 3 shops (= 3 warehouses), each employee works in a different shop, the default warehouse set on the Sales Order should be the default warehouse of the salesperson. So this should be done sale_stock (and not in FSM) Specifications =========== Add a 'Default Warehouse' field on the user only visible if : - sale_stock is installed - the 'multi-warehouses' feature is enabled - domain should only include warehouses which belong to a company the user has access to - not required The field should be editable by a user on his own profile and by the admin on all users. When creating a FSM task from scratch, adding some products creates a SO, the warehouse on the SO should be the default warehouse of the user set on the FSM task. On SO creation, set the 'default warehouse' selected on the user assigned to the SO. If there isn't any 'default warehouse' set on the user, fallback on the current behavior (warehouse with lowest sequence) The field on the res.user should be a property field to allow multicompany usage. Task : 2166382 closes odoo/odoo#44257 Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
-rw-r--r--addons/hr/views/res_users.xml6
-rw-r--r--addons/sale_stock/__manifest__.py1
-rw-r--r--addons/sale_stock/models/__init__.py1
-rw-r--r--addons/sale_stock/models/res_users.py31
-rw-r--r--addons/sale_stock/models/sale_order.py18
-rw-r--r--addons/sale_stock/tests/__init__.py1
-rw-r--r--addons/sale_stock/tests/test_sale_stock_multicompany.py81
-rw-r--r--addons/sale_stock/views/res_users_views.xml44
-rw-r--r--addons/sale_timesheet/wizard/project_create_sale_order.py3
-rw-r--r--addons/sale_timesheet/wizard/project_task_create_sale_order.py3
-rw-r--r--odoo/addons/base/views/res_users_views.xml2
11 files changed, 177 insertions, 14 deletions
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 @@
<h1 position="replace"/>
<widget name="notification_alert" position="replace"/>
<xpath expr="//field[@name='image_1920']" position="replace"/>
- <field name="signature" position="replace" />
- <xpath expr="//group[@name='preference_contact']" position="before">
- <group>
- <field name="signature" />
- </group>
- </xpath>
<xpath expr="//field[@name='company_id']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <data>
+ <record id="res_users_view_form_preferences" model="ir.ui.view">
+ <field name="name">res.users.preferences.form.inherit</field>
+ <field name="model">res.users</field>
+ <field name="inherit_id" ref="base.view_users_form_simple_modif"/>
+ <field name="arch" type="xml">
+ <group name="signature" position="after">
+ <group name="Warehouses">
+ <field name="property_warehouse_id" groups="stock.group_stock_multi_warehouses"/>
+ </group>
+ </group>
+ </field>
+ </record>
+
+ <record id="res_users_view_simple_form" model="ir.ui.view">
+ <field name="name">res.users.simple.form.inherit</field>
+ <field name="model">res.users</field>
+ <field name="inherit_id" ref="base.view_users_simple_form"/>
+ <field name="arch" type="xml">
+ <group name="phone_numbers" position="after">
+ <group name="Warehouses">
+ <field name="property_warehouse_id" groups="stock.group_stock_multi_warehouses"/>
+ </group>
+ </group>
+ </field>
+ </record>
+
+ <record id="res_users_view_form" model="ir.ui.view">
+ <field name="name">res.users.form.inherit</field>
+ <field name="model">res.users</field>
+ <field name="inherit_id" ref="base.view_users_form"/>
+ <field name="arch" type="xml">
+ <group name="messaging" position="after">
+ <group name="Warehouses" string="Inventory" groups="stock.group_stock_multi_warehouses">
+ <field name="property_warehouse_id" groups="stock.group_stock_multi_warehouses"/>
+ </group>
+ </group>
+ </field>
+ </record>
+
+ </data>
+</odoo> \ 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 @@
<label for="company_id" class="oe_edit_only" groups="base.group_multi_company"/>
<field name="company_id" context="{'user_preference': 0}" groups="base.group_multi_company"/>
</div>
- <group>
+ <group name="phone_numbers">
<label for="groups_id" string="Access Rights"
attrs="{'invisible': [('id', '>', 0)]}" groups="base.group_no_one"/>
<div attrs="{'invisible': [('id', '>', 0)]}" groups="base.group_no_one">