[FIX]: Multi Branch : Purchase, Sale stock.
This commit is contained in:
parent
5993da4d2a
commit
effce68e09
@ -5,27 +5,29 @@ from . import test_account_branch
|
||||
class TestJournalEntryBranch(test_account_branch.TestAccountBranch):
|
||||
|
||||
def test_journal_entries_branch(self):
|
||||
journal_ids = self.model_account_journal.search([('code', '=', 'MISC')],
|
||||
limit=1)
|
||||
self.sale_journal_id = \
|
||||
self.env['account.journal'].search([('type', '=', 'sale')])[0]
|
||||
self.account_id = self.env['account.account'].search(
|
||||
[('internal_type', '=', 'receivable')])[0]
|
||||
move_vals = self.env['account.move'].default_get([])
|
||||
lines = [
|
||||
(0, 0, {
|
||||
'name': 'Test',
|
||||
'account_id': self.asset_account.id,
|
||||
'account_id': self.account_id.id,
|
||||
'debit': 0,
|
||||
'credit': 100,
|
||||
'branch_id': self.branch_1.id,
|
||||
}),
|
||||
(0, 0, {
|
||||
'name': 'Test',
|
||||
'account_id': self.asset_account.id,
|
||||
'account_id': self.account_id.id,
|
||||
'debit': 100,
|
||||
'credit': 0,
|
||||
'branch_id': self.branch_1.id,
|
||||
})
|
||||
]
|
||||
move_vals.update({
|
||||
'journal_id': journal_ids and journal_ids.id,
|
||||
'journal_id': self.sale_journal_id.id,
|
||||
'line_ids': lines,
|
||||
})
|
||||
move = self.env['account.move'].sudo(self.user_id.id).create(move_vals)
|
||||
|
@ -23,6 +23,7 @@ Main Features
|
||||
'website': '',
|
||||
'depends': ['base'],
|
||||
'data': [
|
||||
'demo/branch_data.xml',
|
||||
'security/branch_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'views/res_branch_view.xml',
|
||||
|
24
addons/base_branch_company/demo/branch_data.xml
Normal file
24
addons/base_branch_company/demo/branch_data.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="data_branch_1" model="res.branch">
|
||||
<field name="name">your company</field>
|
||||
<field name="code">YC</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="street">80 Broad St</field>
|
||||
<field name="city">Scranton</field>
|
||||
<field name="zip">10004</field>
|
||||
<field name='country_id' ref='base.us'/>
|
||||
<field name='state_id' ref='base.state_us_27'/>
|
||||
<field name="phone">+1 485 123 8989</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="base.user_root" model="res.users">
|
||||
<field name="branch_ids" eval="[(6,0,[ref('data_branch_1'),])]"/>
|
||||
<field name='default_branch_id' ref='data_branch_1'/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</flectra>
|
@ -1,9 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<flectra>
|
||||
<data noupdate="1">
|
||||
|
||||
|
||||
<record id="data_branch_1" model="res.branch">
|
||||
<record id="data_branch_4" model="res.branch">
|
||||
<field name="name">New York</field>
|
||||
<field name="code">NY</field>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
@ -34,10 +33,7 @@
|
||||
<field name='state_id' ref='base.state_us_48'/>
|
||||
<field name="phone">(372) 587-2335</field>
|
||||
</record>
|
||||
<record id="base.user_root" model="res.users">
|
||||
<field name="branch_ids" eval="[(6,0,[ref('data_branch_1'),])]"/>
|
||||
<field name='default_branch_id' ref='data_branch_1'/>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="base.user_demo" model="res.users">
|
||||
<field name="branch_ids" eval="[(6,0,[ref('data_branch_1'),ref('data_branch_2'),ref('data_branch_3')])]"/>
|
||||
|
@ -88,18 +88,34 @@ class Users(models.Model):
|
||||
self.env['res.users'].browse(user).company_id.branch_id
|
||||
return branch_id
|
||||
|
||||
@api.model
|
||||
def _get_branch(self):
|
||||
return self.env.user.default_branch_id
|
||||
|
||||
@api.model
|
||||
def _get_default_branch(self):
|
||||
return self.branch_default_get(self._uid)
|
||||
|
||||
def _branches_count(self):
|
||||
return self.env['res.branch'].sudo().search_count([])
|
||||
|
||||
branch_ids = fields.Many2many('res.branch',
|
||||
'res_branch_users_rel',
|
||||
'user_id',
|
||||
'branch_id',
|
||||
'Branches')
|
||||
'Branches', default=_get_branch,
|
||||
domain="[('company_id','=',company_id)]")
|
||||
default_branch_id = fields.Many2one('res.branch', 'Default branch',
|
||||
default=_get_default_branch,
|
||||
default=_get_branch,
|
||||
domain="[('company_id','=',company_id)"
|
||||
"]")
|
||||
branches_count = fields.Integer(compute='_compute_branches_count',
|
||||
string="Number of Companies",
|
||||
default=_branches_count)
|
||||
|
||||
@api.multi
|
||||
def _compute_branches_count(self):
|
||||
branches_count = self._branches_count()
|
||||
for user in self:
|
||||
user.branches_count = branches_count
|
||||
|
||||
|
@ -87,16 +87,12 @@
|
||||
<field name="model">res.users</field>
|
||||
<field name="inherit_id" ref="base.view_users_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='access_rights']/group[1]" position="replace">
|
||||
<xpath expr="//page[@name='access_rights']/group[1]" position="after">
|
||||
<group>
|
||||
<group string="Multi Companies" attrs="{'invisible': [('companies_count', '<=', 1)]}">
|
||||
<field string="Allowed Companies" name="company_ids" widget="many2many_tags"/>
|
||||
<field string="Current Company" name="company_id" context="{'user_preference': 0}"/>
|
||||
<field string="Companies count" name="companies_count" invisible="1"/>
|
||||
</group>
|
||||
<group string="Allowed Branches">
|
||||
<field name="default_branch_id" domain="[('company_id','=',company_id)]"/>
|
||||
<field name="branch_ids" widget="many2many_tags" domain="[('company_id','=',company_id)]"/>
|
||||
<group string="Allowed Branches" attrs="{'invisible': [('branches_count', '<=', 1)]}">
|
||||
<field name="default_branch_id"/>
|
||||
<field name="branch_ids" widget="many2many_tags"/>
|
||||
<field string="Branches count" name="branches_count" invisible="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
|
@ -78,7 +78,7 @@ class Team(models.Model):
|
||||
values['alias_defaults'] = defaults = safe_eval(self.alias_defaults or "{}")
|
||||
defaults['type'] = 'lead' if has_group_use_lead and self.use_leads else 'opportunity'
|
||||
defaults['team_id'] = self.id
|
||||
defaults['branch_id'] = self.branch_id and self.branch_id.id
|
||||
defaults['branch_id'] = self.branch_id.id
|
||||
return values
|
||||
|
||||
@api.onchange('use_leads', 'use_opportunities')
|
||||
|
@ -16,13 +16,13 @@ class TestTimesheet(TransactionCase):
|
||||
})
|
||||
self.task1 = self.env['project.task'].create({
|
||||
'name': 'Task One',
|
||||
'priority': '0',
|
||||
'priority': 'l',
|
||||
'kanban_state': 'normal',
|
||||
'project_id': self.project_customer.id,
|
||||
})
|
||||
self.task2 = self.env['project.task'].create({
|
||||
'name': 'Task Two',
|
||||
'priority': '1',
|
||||
'priority': 'm',
|
||||
'kanban_state': 'done',
|
||||
'project_id': self.project_customer.id,
|
||||
})
|
||||
|
@ -12,6 +12,7 @@
|
||||
product_qty: 15.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
branch_id: base_branch_company.data_branch_2
|
||||
-
|
||||
!record {model: purchase.order.line, id: purchase_order_line_2}:
|
||||
order_id: purchase_order_1
|
||||
@ -21,6 +22,7 @@
|
||||
product_qty: 5.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
branch_id: base_branch_company.data_branch_2
|
||||
-
|
||||
!record {model: purchase.order.line, id: purchase_order_line_3}:
|
||||
order_id: purchase_order_1
|
||||
@ -30,11 +32,13 @@
|
||||
product_qty: 4.0
|
||||
product_uom: product.product_uom_unit
|
||||
date_planned: !eval time.strftime('%Y-%m-%d')
|
||||
branch_id: base_branch_company.data_branch_2
|
||||
-
|
||||
Creating second order
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_2}:
|
||||
partner_id: base.res_partner_3
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
order_line:
|
||||
- product_id: product.product_delivery_02
|
||||
name: Multimedia Speakers
|
||||
@ -52,6 +56,7 @@
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_3}:
|
||||
partner_id: base.res_partner_12
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
order_line:
|
||||
- product_id: product.product_product_2
|
||||
name: Support Services
|
||||
@ -63,6 +68,7 @@
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_4}:
|
||||
partner_id: base.res_partner_4
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
order_line:
|
||||
- product_id: product.product_delivery_02
|
||||
name: RAM SR2 (kit)
|
||||
@ -86,6 +92,7 @@
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_5}:
|
||||
partner_id: base.res_partner_2
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
order_line:
|
||||
- product_id: product.product_product_22
|
||||
name: Processor Core i5 2.70 Ghz
|
||||
|
@ -7,7 +7,7 @@ from dateutil.relativedelta import relativedelta
|
||||
from flectra import api, fields, models, SUPERUSER_ID, _
|
||||
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from flectra.tools.float_utils import float_is_zero, float_compare
|
||||
from flectra.exceptions import UserError, AccessError
|
||||
from flectra.exceptions import UserError, AccessError, ValidationError
|
||||
from flectra.tools.misc import formatLang
|
||||
from flectra.addons.base.res.res_partner import WARNING_MESSAGE, WARNING_HELP
|
||||
from flectra.addons import decimal_precision as dp
|
||||
@ -15,7 +15,7 @@ from flectra.addons import decimal_precision as dp
|
||||
|
||||
class PurchaseOrder(models.Model):
|
||||
_name = "purchase.order"
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin', 'ir.branch.company.mixin']
|
||||
_description = "Purchase Order"
|
||||
_order = 'date_order desc, id desc'
|
||||
|
||||
@ -95,6 +95,31 @@ class PurchaseOrder(models.Model):
|
||||
if order.picking_ids and all([x.state == 'done' for x in order.picking_ids]):
|
||||
order.is_shipped = True
|
||||
|
||||
@api.constrains('picking_type_id', 'branch_id')
|
||||
def _check_branch(self):
|
||||
for order in self:
|
||||
warehouse_branch_id = order.picking_type_id.warehouse_id.branch_id
|
||||
if order.branch_id and warehouse_branch_id != order.branch_id:
|
||||
raise ValidationError(
|
||||
_('Configuration Error of Branch:\n'
|
||||
'The Purchase Order Branch (%s) and '
|
||||
'the Warehouse Branch (%s) of Deliver To must '
|
||||
'be the same branch!') % (order.branch_id.name,
|
||||
warehouse_branch_id.name)
|
||||
)
|
||||
|
||||
@api.constrains('company_id', 'branch_id')
|
||||
def _check_company(self):
|
||||
for order in self:
|
||||
if order.branch_id and order.company_id != order.branch_id.company_id:
|
||||
raise ValidationError(
|
||||
_('Configuration Error of Company:\n'
|
||||
'The Purchase Order Company (%s) and '
|
||||
'the Company (%s) of Branch must '
|
||||
'be the same company!') % (order.company_id.name,
|
||||
order.branch_id.company_id.name)
|
||||
)
|
||||
|
||||
READONLY_STATES = {
|
||||
'purchase': [('readonly', True)],
|
||||
'done': [('readonly', True)],
|
||||
@ -493,7 +518,11 @@ class PurchaseOrder(models.Model):
|
||||
result = action.read()[0]
|
||||
|
||||
#override the context to get rid of the default filtering
|
||||
result['context'] = {'type': 'in_invoice', 'default_purchase_id': self.id}
|
||||
result['context'] = {
|
||||
'type': 'in_invoice',
|
||||
'default_purchase_id': self.id,
|
||||
'default_branch_id': self.branch_id.id
|
||||
}
|
||||
|
||||
if not self.invoice_ids:
|
||||
# Choose a default account journal in the same currency in case a new invoice is created
|
||||
@ -640,6 +669,10 @@ class PurchaseOrderLine(models.Model):
|
||||
|
||||
orderpoint_id = fields.Many2one('stock.warehouse.orderpoint', 'Orderpoint')
|
||||
move_dest_ids = fields.One2many('stock.move', 'created_purchase_line_id', 'Downstream Moves')
|
||||
branch_id = fields.Many2one(
|
||||
related='order_id.branch_id', string='Branch', store=True,
|
||||
readonly=True
|
||||
)
|
||||
|
||||
@api.multi
|
||||
def _create_or_update_picking(self):
|
||||
|
@ -42,6 +42,10 @@
|
||||
<strong>Order Date:</strong>
|
||||
<p t-field="o.date_order"/>
|
||||
</div>
|
||||
<div name="branch" t-if="o.branch_id" class="col-xs-3">
|
||||
<strong>Branch:</strong>
|
||||
<p t-field="o.branch_id"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class="table table-condensed">
|
||||
|
@ -26,6 +26,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div name="branch" t-if="o.branch_id" class="col-xs-3">
|
||||
<strong>Branch:</strong>
|
||||
<p t-field="o.branch_id"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Request for Quotation <span t-field="o.name"/></h2>
|
||||
|
||||
<table class="table table-condensed">
|
||||
|
@ -10,6 +10,7 @@ from flectra import api, fields, models, tools
|
||||
|
||||
class PurchaseReport(models.Model):
|
||||
_name = "purchase.report"
|
||||
_inherit = ['ir.branch.company.mixin']
|
||||
_description = "Purchases Orders"
|
||||
_auto = False
|
||||
_order = 'date_order desc, price_total desc'
|
||||
@ -64,6 +65,7 @@ class PurchaseReport(models.Model):
|
||||
s.partner_id as partner_id,
|
||||
s.create_uid as user_id,
|
||||
s.company_id as company_id,
|
||||
s.branch_id as branch_id,
|
||||
s.fiscal_position_id as fiscal_position_id,
|
||||
l.product_id,
|
||||
p.product_tmpl_id,
|
||||
@ -99,6 +101,7 @@ class PurchaseReport(models.Model):
|
||||
(cr.date_end is null or cr.date_end > coalesce(s.date_order, now())))
|
||||
group by
|
||||
s.company_id,
|
||||
s.branch_id,
|
||||
s.create_uid,
|
||||
s.partner_id,
|
||||
u.factor,
|
||||
|
@ -75,5 +75,30 @@
|
||||
<field name="domain_force">[('order_id.message_partner_ids','child_of',[user.commercial_partner_id.id])]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_portal'))]"/>
|
||||
</record>
|
||||
|
||||
<!-- Multi Branch Rules -->
|
||||
<record id="purchase_order_multi_branch_rule" model="ir.rule">
|
||||
<field name="name">Purchase Order multi-branch</field>
|
||||
<field name="model_id" ref="model_purchase_order"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('branch_id', '=', False), '|', ('branch_id', '=', user.default_branch_id.id),
|
||||
('branch_id', 'in', user.branch_ids.ids)]</field>
|
||||
</record>
|
||||
|
||||
<record id="purchase_order_line_multi_branch_rule" model="ir.rule">
|
||||
<field name="name">Purchase Order Line multi-branch</field>
|
||||
<field name="model_id" ref="model_purchase_order_line"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('branch_id', '=', False), '|', ('branch_id', '=', user.default_branch_id.id),
|
||||
('branch_id', 'in', user.branch_ids.ids)]</field>
|
||||
</record>
|
||||
|
||||
<record id="purchase_order_report_multi_branch_rule" model="ir.rule">
|
||||
<field name="name">Purchase Order Analysis multi-branch</field>
|
||||
<field name="model_id" ref="model_purchase_report"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('branch_id', '=', False), '|', ('branch_id', '=', user.default_branch_id.id),
|
||||
('branch_id', 'in', user.branch_ids.ids)]</field>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
||||
|
@ -6,3 +6,5 @@ from . import test_purchase_order
|
||||
from . import test_create_picking
|
||||
from . import test_purchase_lead_time
|
||||
from . import test_stockvaluation
|
||||
from . import test_purchase_branch
|
||||
from . import test_user_authorization
|
||||
|
70
addons/purchase/tests/test_purchase_branch.py
Normal file
70
addons/purchase/tests/test_purchase_branch.py
Normal file
@ -0,0 +1,70 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Flectra. See LICENSE file for full copyright and licensing details.
|
||||
import time
|
||||
from flectra.addons.purchase.tests import test_purchase_order
|
||||
|
||||
|
||||
class TestPurchaseBranchAuthentication(test_purchase_order.TestPurchaseOrder):
|
||||
def setUp(self):
|
||||
super(TestPurchaseBranchAuthentication, self).setUp()
|
||||
self.user_1 = self.create_test_users(self.main_company, 'user_1', self.branch_1, [self.branch_1],
|
||||
[self.purchase_user_group, self.stock_user_group])
|
||||
self.user_2 = self.create_test_users(self.child_company, 'user_2', self.branch_2, [self.branch_2],
|
||||
[self.purchase_user_group, self.stock_user_group])
|
||||
product_list = [(self.product_id_1, 500),
|
||||
(self.product_id_2, 1000),
|
||||
(self.product_id_3, 800)]
|
||||
order_lines = []
|
||||
for product_id, quantity in product_list:
|
||||
line_values = {
|
||||
'name': product_id.name,
|
||||
'product_id': product_id.id,
|
||||
'price_unit': 80,
|
||||
'product_qty': quantity,
|
||||
'product_uom': product_id.uom_id.id,
|
||||
'date_planned': self.current_time,
|
||||
}
|
||||
order_lines.append((0, 0, line_values))
|
||||
self.purchase = self.PurchaseOrder.sudo(self.user_1).create({
|
||||
'partner_id': self.partner_id.id,
|
||||
'company_id': self.main_company.id,
|
||||
'branch_id': self.branch_1.id,
|
||||
'order_line': order_lines,
|
||||
|
||||
})
|
||||
|
||||
self.purchase.sudo(self.user_1).button_confirm()
|
||||
self.create_purchase_invoice(self.partner_id, self.purchase, self.account)
|
||||
|
||||
def create_test_users(self, company_id, login, branch_id, branch_ids, group_ids):
|
||||
group_ids = [group_id.id for group_id in group_ids]
|
||||
user_obj = \
|
||||
self.env['res.users'].with_context({'no_reset_password': True}). \
|
||||
create({
|
||||
'company_id': company_id.id,
|
||||
'company_ids': [(4, company_id.id)],
|
||||
'default_branch_id': branch_id.id,
|
||||
'branch_ids': [(4, branch.id) for branch in branch_ids],
|
||||
'name': 'Alex Purchase User',
|
||||
'login': login,
|
||||
'password': '123',
|
||||
'email': 'alex@yourcompany.com',
|
||||
'groups_id': [(6, 0, group_ids)]
|
||||
})
|
||||
return user_obj.id
|
||||
|
||||
def create_purchase_invoice(self, partner_id, purchase, account):
|
||||
context = {
|
||||
'active_model': 'purchase.order',
|
||||
'active_ids': purchase.ids,
|
||||
'active_id': purchase.id,
|
||||
|
||||
}
|
||||
invoice_vals = {
|
||||
'type': 'in_invoice',
|
||||
'partner_id': partner_id.id,
|
||||
'purchase_id': purchase.id,
|
||||
'account_id': self.partner_id.property_account_payable_id.id,
|
||||
}
|
||||
self.env['account.invoice'].with_context(context).create(invoice_vals)
|
||||
return True
|
@ -13,6 +13,9 @@ class TestPurchaseLeadTime(TestPurchase):
|
||||
""" To check dates, set product's Delivery Lead Time
|
||||
and company's Purchase Lead Time."""
|
||||
|
||||
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
|
||||
self.warehouse_1.write({'branch_id': self.branch_1.id})
|
||||
|
||||
company = self.env.ref('base.main_company')
|
||||
|
||||
# Update company with Purchase Lead Time
|
||||
@ -49,6 +52,9 @@ class TestPurchaseLeadTime(TestPurchase):
|
||||
and different Delivery Lead Time."""
|
||||
|
||||
# Make procurement request from product_1's form view, create procurement and check it's state
|
||||
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
|
||||
self.warehouse_1.write({'branch_id': self.branch_1.id})
|
||||
|
||||
date_planned1 = fields.Datetime.to_string(fields.datetime.now() + timedelta(days=10))
|
||||
self._create_make_procurement(self.product_1, 10.00, date_planned=date_planned1)
|
||||
purchase1 = self.env['purchase.order.line'].search([('product_id', '=', self.product_1.id)], limit=1).order_id
|
||||
@ -96,6 +102,8 @@ class TestPurchaseLeadTime(TestPurchase):
|
||||
and warehouse route's delay."""
|
||||
|
||||
# Update warehouse_1 with Incoming Shipments 3 steps
|
||||
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
|
||||
self.warehouse_1.write({'branch_id': self.branch_1.id})
|
||||
self.warehouse_1.write({'reception_steps': 'three_steps'})
|
||||
|
||||
# Set delay on push rule
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import time
|
||||
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from flectra.addons.account.tests.account_test_classes import AccountingTestCase
|
||||
|
||||
@ -19,6 +19,15 @@ class TestPurchaseOrder(AccountingTestCase):
|
||||
self.partner_id = self.env.ref('base.res_partner_1')
|
||||
self.product_id_1 = self.env.ref('product.product_product_8')
|
||||
self.product_id_2 = self.env.ref('product.product_product_11')
|
||||
self.product_id_3 = self.env.ref('product.product_product_9')
|
||||
self.current_time = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
self.main_company = self.env.ref('base.main_company')
|
||||
self.child_company = self.env.ref('stock.res_company_1')
|
||||
self.purchase_user_group = self.env.ref('purchase.group_purchase_user')
|
||||
self.stock_user_group = self.env.ref('stock.group_stock_user')
|
||||
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
|
||||
self.branch_2 = self.env.ref('base_branch_company.data_branch_2')
|
||||
self.account = self.env.ref('l10n_generic_coa.conf_a_pay')
|
||||
|
||||
(self.product_id_1 | self.product_id_2).write({'purchase_method': 'purchase'})
|
||||
self.po_vals = {
|
||||
|
22
addons/purchase/tests/test_user_authorization.py
Normal file
22
addons/purchase/tests/test_user_authorization.py
Normal file
@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo,Flectra. See LICENSE file for full copyright and licensing details.
|
||||
from flectra.addons.purchase.tests import \
|
||||
test_purchase_branch
|
||||
|
||||
|
||||
class TestUserAuthorization(test_purchase_branch.TestPurchaseBranchAuthentication):
|
||||
def test_user_authorization(self):
|
||||
|
||||
purchase_ids = self.PurchaseOrder.sudo(self.user_2).search([('branch_id', '=', self.branch_1.id)]).ids
|
||||
self.assertEqual(purchase_ids, [], 'User %s wrongly accessed Purchase order %s ' % (self.user_2, str(purchase_ids)))
|
||||
picking_ids = self.env['stock.picking'].sudo(self.user_2).search([('id', 'in', self.purchase.picking_ids.ids)]).ids
|
||||
self.assertEqual(picking_ids, [], 'User %s wrongly accessed Pickings %s ' % (self.user_2, str(picking_ids)))
|
||||
invoice_ids = self.AccountInvoice.sudo(self.user_2).search([('purchase_id', '=', self.purchase.id)]).ids
|
||||
self.assertEqual(invoice_ids, [], 'User %s wrongly accessed Invoices %s ' % (self.user_2, str(invoice_ids)))
|
||||
|
||||
purchase_ids = self.PurchaseOrder.sudo(self.user_1).search([('branch_id', '=', self.branch_1.id)]).ids
|
||||
self.assertNotEqual(purchase_ids, [], 'User %s Should have accessed to Purchase Orders %s ' % (self.user_1, str(purchase_ids)))
|
||||
picking_ids = self.env['stock.picking'].sudo(self.user_1).search([('id', 'in', self.purchase.picking_ids.ids)]).ids
|
||||
self.assertNotEqual(picking_ids, [], 'User %s Should have accessed to Pickings %s ' % (self.user_1, str(picking_ids)))
|
||||
invoice_ids = self.AccountInvoice.sudo(self.user_1).search([('purchase_id', '=', self.purchase.id)]).ids
|
||||
self.assertNotEqual(invoice_ids, [], 'User %s Should have accessed to Invoices %s ' % (self.user_1, str(invoice_ids)))
|
@ -284,6 +284,7 @@
|
||||
<field name="dest_address_id" groups="stock.group_stock_multi_locations" attrs="{'invisible': [('default_location_dest_id_usage', '!=', 'customer')], 'required': [('default_location_dest_id_usage', '=', 'customer')]}"/>
|
||||
<field name="default_location_dest_id_usage" invisible="1"/>
|
||||
<field name="incoterm_id"/>
|
||||
<field name="branch_id" options="{'no_create': True, 'no_create_edit': True}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="invoice_status"/>
|
||||
@ -336,6 +337,7 @@
|
||||
<filter string="Vendor" domain="[]" context="{'group_by':'partner_id'}"/>
|
||||
<filter string="Order Date" domain="[]" context="{'group_by':'date_order'}"/>
|
||||
<filter string="Expected Date" domain="[]" context="{'group_by':'date_planned'}"/>
|
||||
<filter name="groupby_branch" string="Branch" domain="[]" context="{'group_by': 'branch_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
@ -388,6 +390,7 @@
|
||||
<field name="date_order" />
|
||||
<field name="partner_id"/>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="date_planned" invisible="context.get('quotation_only', False)"/>
|
||||
<field name="origin"/>
|
||||
<field name="amount_untaxed" sum="Total Untaxed amount" string="Untaxed" widget="monetary"/>
|
||||
|
@ -6,7 +6,6 @@ from flectra import api, fields, models, tools
|
||||
|
||||
class PosSaleReport(models.Model):
|
||||
_name = "report.all.channels.sales"
|
||||
_inherit = ['ir.branch.company.mixin']
|
||||
_description = "All sales orders grouped by sales channels"
|
||||
_auto = False
|
||||
|
||||
@ -38,7 +37,6 @@ class PosSaleReport(models.Model):
|
||||
so.user_id AS user_id,
|
||||
pt.categ_id AS categ_id,
|
||||
so.company_id AS company_id,
|
||||
so.branch_id AS branch_id,
|
||||
sol.price_total / COALESCE(cr.rate, 1.0) AS price_total,
|
||||
so.pricelist_id AS pricelist_id,
|
||||
rp.country_id AS country_id,
|
||||
@ -77,7 +75,6 @@ class PosSaleReport(models.Model):
|
||||
user_id,
|
||||
categ_id,
|
||||
company_id,
|
||||
branch_id,
|
||||
price_total,
|
||||
pricelist_id,
|
||||
analytic_account_id,
|
||||
|
@ -12,17 +12,49 @@ class TestSaleBranch(common.TransactionCase):
|
||||
|
||||
self.payment_model_obj = self.env['sale.advance.payment.inv']
|
||||
|
||||
IrModelData = self.env['ir.model.data']
|
||||
journal_obj = self.env['account.journal']
|
||||
account_obj = self.env['account.account']
|
||||
|
||||
user_type_id = IrModelData.xmlid_to_res_id(
|
||||
'account.data_account_type_revenue')
|
||||
account_rev_id = account_obj.create(
|
||||
{'code': 'X2020', 'name': 'Sales - Test Sales Account',
|
||||
'user_type_id': user_type_id, 'reconcile': True})
|
||||
user_type_id = IrModelData.xmlid_to_res_id(
|
||||
'account.data_account_type_receivable')
|
||||
account_recv_id = account_obj.create(
|
||||
{'code': 'X1012', 'name': 'Sales - Test Reicv Account',
|
||||
'user_type_id': user_type_id, 'reconcile': True})
|
||||
|
||||
self.apple_product = self.env.ref('product.product_product_7')
|
||||
self.apple_product.write({'invoice_policy': 'order'})
|
||||
|
||||
# Add account to product
|
||||
product_template_id = self.apple_product.product_tmpl_id
|
||||
product_template_id.write(
|
||||
{'property_account_income_id': account_rev_id})
|
||||
|
||||
self.sale_customer = self.env.ref('base.res_partner_2')
|
||||
self.sale_pricelist = self.env.ref('product.list0')
|
||||
|
||||
# Create Sales Journal
|
||||
company_id = IrModelData.xmlid_to_res_id('base.main_company') or False
|
||||
journal_obj.create(
|
||||
{'name': 'Sales Journal - Test', 'code': 'STSJ', 'type': 'sale',
|
||||
'company_id': company_id})
|
||||
self.sale_customer.write({'property_account_receivable_id': account_recv_id})
|
||||
|
||||
self.sale_user_group = self.env.ref('sales_team.group_sale_manager')
|
||||
self.account_user_group = self.env.ref('account.group_account_invoice')
|
||||
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
|
||||
self.branch_2 = self.env.ref('base_branch_company.data_branch_2')
|
||||
self.branch_3 = self.env.ref('base_branch_company.data_branch_3')
|
||||
|
||||
self.sale_customer = self.env.ref('base.res_partner_2')
|
||||
self.sale_pricelist = self.env.ref('product.list0')
|
||||
|
||||
self.apple_product = self.env.ref('product.product_product_7')
|
||||
self.apple_product.write({'invoice_policy': 'order'})
|
||||
|
||||
# self.apple_product = self.env.ref('product.product_product_7')
|
||||
# self.apple_product.write({'invoice_policy': 'order'})
|
||||
|
||||
self.user_1 = self.create_sale_user(
|
||||
self.main_company, 'user_1', self.branch_1,
|
||||
|
@ -5,7 +5,7 @@ from datetime import datetime, timedelta
|
||||
|
||||
from flectra import api, fields, models, _
|
||||
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_compare
|
||||
from flectra.exceptions import UserError
|
||||
from flectra.exceptions import UserError, ValidationError
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
|
@ -133,6 +133,7 @@
|
||||
<field model="res.company" name="name" search="[]" use="name"/>
|
||||
<field name="partner_id" ref="base.main_partner"/>
|
||||
<field name="code">WH</field>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
</record>
|
||||
|
||||
<record id="sequence_mrp_op" model="ir.sequence">
|
||||
|
@ -1,3 +1,9 @@
|
||||
-
|
||||
!python {model: stock.warehouse, id: warehouse0}: |
|
||||
warehouse = self.env['stock.warehouse'].browse(ref('warehouse0'))
|
||||
branch_id = self.env['res.branch'].browse(ref('base_branch_company.data_branch_1'))
|
||||
warehouse.write({'branch_id': branch_id.id})
|
||||
|
||||
-
|
||||
!python {model: res.partner, id: base.main_partner}: |
|
||||
main_warehouse = self.env['stock.warehouse'].browse(ref('warehouse0'))
|
||||
@ -30,4 +36,15 @@
|
||||
companies = self.search([('internal_transit_location_id', '=', False)])
|
||||
for company in companies:
|
||||
company.create_transit_location()
|
||||
-
|
||||
!python {model: stock.location, id: False}: |
|
||||
branch_id = self.env['res.branch'].browse(ref('base_branch_company.data_branch_1'))
|
||||
self.browse([
|
||||
ref('stock_location_stock'),
|
||||
ref('stock_location_output'),
|
||||
ref('stock_location_company'),
|
||||
|
||||
]).write({'branch_id': branch_id.id})
|
||||
|
||||
|
||||
|
||||
|
@ -167,13 +167,49 @@
|
||||
<field name="name">My Company, Chicago</field>
|
||||
</record>
|
||||
|
||||
<record id="branch_shop0" model="res.branch">
|
||||
<field name="name">Chicago</field>
|
||||
<field name="code">CH</field>
|
||||
<field name="company_id" ref="stock.res_company_1"/>
|
||||
</record>
|
||||
|
||||
<record id="stock_warehouse_shop0" model="stock.warehouse">
|
||||
<field name="name">Chicago Warehouse</field>
|
||||
<field name="partner_id" ref="res_partner_address_41"/>
|
||||
<field name="company_id" ref="res_company_1"/>
|
||||
<field name="branch_id" ref="branch_shop0"/>
|
||||
<field name="code">Chic</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- Multi Branch -->
|
||||
|
||||
<record id="stock.stock_location_14" model="stock.location">
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
</record>
|
||||
|
||||
<record id="stock.stock_location_components" model="stock.location">
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
</record>
|
||||
|
||||
<!--NY-->
|
||||
<record id="stock_warehouse_ny" model="stock.warehouse">
|
||||
<field name="name">New York Warehouse</field>
|
||||
<field name="code">NY</field>
|
||||
<field name="partner_id" ref="base.main_partner"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
|
||||
</record>
|
||||
|
||||
<!-- WA -->
|
||||
<record id="stock_warehouse_WW" model="stock.warehouse">
|
||||
<field name="name">Washington Warehouse</field>
|
||||
<field name="code">WA</field>
|
||||
<field name="partner_id" ref="base.main_partner"/>
|
||||
<field name="company_id" ref="base.main_company"/>
|
||||
<field name="branch_id" ref="base_branch_company.data_branch_2"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</flectra>
|
||||
|
||||
|
@ -14,10 +14,18 @@
|
||||
self.create(xml_record)
|
||||
#avoid the xml id and the associated resource being dropped by the orm by manually making a hit on it
|
||||
self._update_dummy(xml_record['model'], xml_record['module'], xml_record['name'])
|
||||
|
||||
-
|
||||
!python {model: stock.location, id: stock_location_shop0}: |
|
||||
picking = self.env['stock.location'].browse(ref('stock_location_shop0'))
|
||||
branch_id = self.env['res.branch'].browse(ref('branch_shop0'))
|
||||
picking.write({'branch_id': branch_id.id})
|
||||
|
||||
-
|
||||
!record {model: stock.location, id: location_refrigerator_small}:
|
||||
name: Small Refrigerator
|
||||
usage: internal
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
location_id: stock_location_14
|
||||
-
|
||||
!record {model: product.product, id: product_icecream}:
|
||||
@ -201,6 +209,8 @@
|
||||
picking_type_id: chi_picking_type_in
|
||||
origin: 'incoming_chicago_warehouse'
|
||||
partner_id: base.res_partner_1
|
||||
company_id: stock.res_company_1
|
||||
branch_id: stock.branch_shop0
|
||||
location_id: stock.stock_location_suppliers
|
||||
location_dest_id: stock.stock_location_shop0
|
||||
move_lines:
|
||||
@ -215,7 +225,9 @@
|
||||
!record {model: stock.picking, id: incomming_chicago_warehouse1}:
|
||||
picking_type_id: chi_picking_type_in
|
||||
partner_id: base.res_partner_1
|
||||
branch_id: stock.branch_shop0
|
||||
location_id: stock.stock_location_suppliers
|
||||
company_id: stock.res_company_1
|
||||
location_dest_id: stock.stock_location_shop0
|
||||
move_lines:
|
||||
- product_id: product.product_delivery_01
|
||||
@ -235,6 +247,8 @@
|
||||
!record {model: stock.picking, id: incomming_chicago_warehouse2}:
|
||||
picking_type_id: chi_picking_type_in
|
||||
partner_id: base.res_partner_1
|
||||
branch_id: stock.branch_shop0
|
||||
company_id: stock.res_company_1
|
||||
location_id: stock.stock_location_suppliers
|
||||
location_dest_id: stock.stock_location_shop0
|
||||
move_lines:
|
||||
@ -247,6 +261,8 @@
|
||||
-
|
||||
!record {model: stock.picking, id: incomming_chicago_warehouse3}:
|
||||
picking_type_id: chi_picking_type_in
|
||||
branch_id: stock.branch_shop0
|
||||
company_id: stock.res_company_1
|
||||
origin: 'chicago_warehouse'
|
||||
partner_id: base.res_partner_1
|
||||
date: !eval "'%s-%s-2' % ((datetime.now()-timedelta(days=30)).month,(datetime.now()-timedelta(days=30)).month)"
|
||||
@ -265,6 +281,8 @@
|
||||
!record {model: stock.picking, id: outgoing_chicago_warehouse}:
|
||||
picking_type_id: chi_picking_type_out
|
||||
origin: 'outgoing_chicago_warehouse'
|
||||
branch_id: stock.branch_shop0
|
||||
company_id: stock.res_company_1
|
||||
partner_id: base.res_partner_1
|
||||
location_id: stock.stock_location_shop0
|
||||
location_dest_id: stock.stock_location_customers
|
||||
@ -279,6 +297,8 @@
|
||||
!record {model: stock.picking, id: outgoing_chicago_warehouse1}:
|
||||
picking_type_id: chi_picking_type_out
|
||||
origin: 'outgoing_shipment_chicago_warehouse'
|
||||
company_id: stock.res_company_1
|
||||
branch_id: stock.branch_shop0
|
||||
partner_id: base.res_partner_1
|
||||
location_id: stock.stock_location_shop0
|
||||
location_dest_id: stock.stock_location_customers
|
||||
@ -299,6 +319,8 @@
|
||||
!record {model: stock.picking, id: outgoing_chicago_warehouse2}:
|
||||
picking_type_id: chi_picking_type_out
|
||||
origin: 'chicago_warehouse'
|
||||
company_id: stock.res_company_1
|
||||
branch_id: stock.branch_shop0
|
||||
partner_id: base.res_partner_1
|
||||
location_id: stock.stock_location_shop0
|
||||
location_dest_id: stock.stock_location_customers
|
||||
@ -312,6 +334,8 @@
|
||||
-
|
||||
!record {model: stock.picking, id: outgoing_chicago_warehouse3}:
|
||||
picking_type_id: chi_picking_type_out
|
||||
company_id: stock.res_company_1
|
||||
branch_id: stock.branch_shop0
|
||||
origin: 'outgoing chicago warehouse'
|
||||
location_id: stock.stock_location_shop0
|
||||
location_dest_id: stock.stock_location_customers
|
||||
|
@ -1,11 +1,13 @@
|
||||
-
|
||||
!record {model: stock.location, id: stock_location_14}:
|
||||
name: Shelf 2
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
posx: 0
|
||||
|
||||
-
|
||||
!record {model: stock.location, id: stock_location_components}:
|
||||
name: Shelf 1
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
posx: 0
|
||||
|
||||
-
|
||||
|
@ -2,19 +2,23 @@
|
||||
!record {model: stock.location, id: location_order}:
|
||||
name: Order Processing
|
||||
usage: internal
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
location_id: stock.stock_location_company
|
||||
-
|
||||
!record {model: stock.location, id: location_dispatch_zone}:
|
||||
name: Dispatch Zone
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
usage: internal
|
||||
location_id: location_order
|
||||
-
|
||||
!record {model: stock.location, id: location_gate_a}:
|
||||
name: Gate A
|
||||
usage: internal
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
location_id: location_dispatch_zone
|
||||
-
|
||||
!record {model: stock.location, id: location_gate_b}:
|
||||
name: Gate B
|
||||
branch_id: base_branch_company.data_branch_1
|
||||
usage: internal
|
||||
location_id: location_dispatch_zone
|
||||
|
@ -34,6 +34,12 @@ class Company(models.Model):
|
||||
|
||||
# multi-company rules prevents creating warehouse and sub-locations
|
||||
self.env['stock.warehouse'].check_access_rights('create')
|
||||
self.env['stock.warehouse'].sudo().create({'name': company.name, 'code': company.name[:5], 'company_id': company.id, 'partner_id': company.partner_id.id})
|
||||
self.env['stock.warehouse'].sudo().create({'name': company.name,
|
||||
'code': company.name[:5],
|
||||
'company_id': company.id,
|
||||
'partner_id':
|
||||
company.partner_id.id,
|
||||
'branch_id':
|
||||
company.branch_id.id})
|
||||
company.create_transit_location()
|
||||
return company
|
||||
|
@ -54,6 +54,10 @@ class Inventory(models.Model):
|
||||
readonly=True, required=True,
|
||||
states={'draft': [('readonly', False)]},
|
||||
default=_default_location_id)
|
||||
|
||||
branch_id = fields.Many2one('res.branch', 'Branch',
|
||||
related='location_id.branch_id', index=True, readonly=True,
|
||||
store=True)
|
||||
product_id = fields.Many2one(
|
||||
'product.product', 'Inventoried Product',
|
||||
readonly=True,
|
||||
@ -295,6 +299,9 @@ class InventoryLine(models.Model):
|
||||
inventory_id = fields.Many2one(
|
||||
'stock.inventory', 'Inventory',
|
||||
index=True, ondelete='cascade')
|
||||
branch_id = fields.Many2one('res.branch', 'Branch',
|
||||
related='inventory_id.branch_id', index=True,
|
||||
readonly=True, store=True)
|
||||
partner_id = fields.Many2one('res.partner', 'Owner')
|
||||
product_id = fields.Many2one(
|
||||
'product.product', 'Product',
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
from datetime import datetime
|
||||
from dateutil import relativedelta
|
||||
from flectra.exceptions import UserError
|
||||
from flectra.exceptions import UserError, ValidationError
|
||||
|
||||
from flectra import api, fields, models, _
|
||||
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
@ -66,6 +66,7 @@ class Location(models.Model):
|
||||
removal_strategy_id = fields.Many2one('product.removal', 'Removal Strategy', help="Defines the default method used for suggesting the exact location (shelf) where to take the products from, which lot etc. for this location. This method can be enforced at the product category level, and a fallback is made on the parent locations if none is set here.")
|
||||
putaway_strategy_id = fields.Many2one('product.putaway', 'Put Away Strategy', help="Defines the default method used for suggesting the exact location (shelf) where to store the products. This method can be enforced at the product category level, and a fallback is made on the parent locations if none is set here.")
|
||||
barcode = fields.Char('Barcode', copy=False, oldname='loc_barcode')
|
||||
branch_id = fields.Many2one('res.branch', 'Branch', ondelete="restrict")
|
||||
quant_ids = fields.One2many('stock.quant', 'location_id')
|
||||
|
||||
_sql_constraints = [('barcode_company_uniq', 'unique (barcode,company_id)', 'The barcode for a location must be unique per company !')]
|
||||
@ -85,6 +86,60 @@ class Location(models.Model):
|
||||
raise UserError(_("This location's usage cannot be changed to view as it contains products."))
|
||||
return super(Location, self).write(values)
|
||||
|
||||
@api.multi
|
||||
@api.constrains('branch_id', 'location_id')
|
||||
def _check_parent_branch(self):
|
||||
for record in self:
|
||||
if (
|
||||
record.location_id and
|
||||
record.location_id.usage == 'internal' and
|
||||
record.branch_id and record.branch_id != record.location_id.branch_id
|
||||
):
|
||||
raise UserError(
|
||||
_('Configuration Error of Branch:\n'
|
||||
'The Location Branch (%s) and '
|
||||
'the Branch (%s) of Parent Location must '
|
||||
'be the same branch!') % (recordord.branch_id.name,
|
||||
recordord.location_id.branch_id.name)
|
||||
)
|
||||
|
||||
@api.multi
|
||||
@api.constrains('branch_id')
|
||||
def _check_warehouse_branch(self):
|
||||
for record in self:
|
||||
warehouse_obj = self.env['stock.warehouse']
|
||||
warehouses_ids = warehouse_obj.search(
|
||||
['|', '|', ('wh_input_stock_loc_id', '=', record.ids[0]),
|
||||
('lot_stock_id', 'in', record.ids),
|
||||
('wh_output_stock_loc_id', 'in', record.ids)])
|
||||
for warehouse_id in warehouses_ids:
|
||||
if record.branch_id and record.branch_id != warehouse_id.branch_id:
|
||||
raise ValidationError(
|
||||
_('Configuration Error of Branch:\n'
|
||||
'The Location Branch (%s) and '
|
||||
'the Branch (%s) of Warehouse must '
|
||||
'be the same branch!') % (record.branch_id.name,
|
||||
warehouse_id.branch_id.name)
|
||||
)
|
||||
if record.usage != 'internal' and record.branch_id:
|
||||
raise UserError(
|
||||
_('Configuration error of Branch:\n'
|
||||
'The branch (%s) should be assigned to internal locations'
|
||||
) % (record.branch_id.name))
|
||||
|
||||
@api.multi
|
||||
@api.constrains('company_id', 'branch_id')
|
||||
def _check_company_branch(self):
|
||||
for record in self:
|
||||
if record.branch_id and record.company_id != record.branch_id.company_id:
|
||||
raise UserError(
|
||||
_('Configuration Error of Company:\n'
|
||||
'The Company (%s) in the Stock Location and '
|
||||
'the Company (%s) of Branch must '
|
||||
'be the same company!') % (record.company_id.name,
|
||||
record.branch_id.company_id.name)
|
||||
)
|
||||
|
||||
def name_get(self):
|
||||
ret_list = []
|
||||
for location in self:
|
||||
|
@ -158,6 +158,35 @@ class StockMove(models.Model):
|
||||
is_initial_demand_editable = fields.Boolean('Is initial demand editable', compute='_compute_is_initial_demand_editable')
|
||||
is_quantity_done_editable = fields.Boolean('Is quantity done editable', compute='_compute_is_quantity_done_editable')
|
||||
reference = fields.Char(compute='_compute_reference', string="Reference", store=True)
|
||||
branch_id = fields.Many2one(
|
||||
related='location_id.branch_id', store=True,
|
||||
string='Source Location Branch',
|
||||
)
|
||||
branch_dest_id = fields.Many2one(
|
||||
related='location_dest_id.branch_id', store=True,
|
||||
string='Dest. Location Branch',
|
||||
)
|
||||
|
||||
@api.multi
|
||||
@api.constrains('branch_id', 'location_id', 'picking_id',
|
||||
'branch_dest_id', 'location_dest_id')
|
||||
def _check_stock_move_branch(self):
|
||||
for record in self:
|
||||
if not record.branch_id:
|
||||
return True
|
||||
if (record.location_id and
|
||||
record.location_id.branch_id and
|
||||
record.picking_id and record.branch_id != record.picking_id.branch_id
|
||||
) and (
|
||||
record.location_dest_id and
|
||||
record.location_dest_id.branch_id and
|
||||
record.picking_id and record.branch_dest_id != record.picking_id.branch_id
|
||||
):
|
||||
raise UserError(
|
||||
_('Configuration error of Branch:\nThe Stock moves must '
|
||||
'be related to a source or destination location '
|
||||
'that belongs to the requesting Branch.')
|
||||
)
|
||||
|
||||
@api.depends('picking_id.is_locked')
|
||||
def _compute_is_locked(self):
|
||||
|
@ -9,7 +9,7 @@ from itertools import groupby
|
||||
from flectra import api, fields, models, _
|
||||
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from flectra.tools.float_utils import float_compare, float_round
|
||||
from flectra.exceptions import UserError
|
||||
from flectra.exceptions import UserError, ValidationError
|
||||
from flectra.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES
|
||||
from operator import itemgetter
|
||||
|
||||
@ -263,6 +263,11 @@ class Picking(models.Model):
|
||||
index=True, required=True,
|
||||
states={'done': [('readonly', True)], 'cancel': [('readonly', True)]})
|
||||
|
||||
branch_id = fields.Many2one('res.branch', 'Branch', ondelete="restrict",
|
||||
default=lambda self: self.env['res.users']._get_default_branch(),
|
||||
states={'done': [('readonly', True)],
|
||||
'cancel': [('readonly', True)]})
|
||||
|
||||
move_line_ids = fields.One2many('stock.move.line', 'picking_id', 'Operations')
|
||||
|
||||
move_line_exist = fields.Boolean(
|
||||
@ -305,6 +310,31 @@ class Picking(models.Model):
|
||||
('name_uniq', 'unique(name, company_id)', 'Reference must be unique per company!'),
|
||||
]
|
||||
|
||||
@api.constrains('picking_type_id', 'branch_id')
|
||||
def _check_picking_type_branch(self):
|
||||
for order in self:
|
||||
warehouse_branch_id = order.picking_type_id.warehouse_id.branch_id
|
||||
if warehouse_branch_id and order.branch_id and warehouse_branch_id != order.branch_id:
|
||||
raise ValidationError(
|
||||
_('Configuration Error of Branch:\n'
|
||||
'The Picking Branch (%s) and '
|
||||
'the Warehouse Branch (%s) of Picking Type must '
|
||||
'be the same branch!') % (order.branch_id.name,
|
||||
warehouse_branch_id.name)
|
||||
)
|
||||
|
||||
@api.constrains('company_id', 'branch_id')
|
||||
def _check_company(self):
|
||||
for order in self:
|
||||
if order.branch_id and order.company_id != order.branch_id.company_id:
|
||||
raise ValidationError(
|
||||
_('Configuration Error of Company:\n'
|
||||
'The Stock Picking Company (%s) and '
|
||||
'the Company (%s) of Branch must '
|
||||
'be the same company!') % (order.company_id.name,
|
||||
order.branch_id.company_id.name)
|
||||
)
|
||||
|
||||
@api.depends('picking_type_id.show_operations')
|
||||
def _compute_show_operations(self):
|
||||
for picking in self:
|
||||
@ -873,7 +903,9 @@ class Picking(models.Model):
|
||||
'res_model': 'stock.scrap',
|
||||
'view_id': self.env.ref('stock.stock_scrap_form_view2').id,
|
||||
'type': 'ir.actions.act_window',
|
||||
'context': {'default_picking_id': self.id, 'product_ids': products.ids},
|
||||
'context': {'default_picking_id': self.id,
|
||||
'default_branch_id': self.branch_id and self.branch_id.id,
|
||||
'product_ids': products.ids},
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,8 @@ class StockQuant(models.Model):
|
||||
location_id = fields.Many2one(
|
||||
'stock.location', 'Location',
|
||||
auto_join=True, ondelete='restrict', readonly=True, required=True)
|
||||
branch_id = fields.Many2one(related='location_id.branch_id',
|
||||
string='Branch', )
|
||||
lot_id = fields.Many2one(
|
||||
'stock.production.lot', 'Lot/Serial Number',
|
||||
ondelete='restrict', readonly=True)
|
||||
|
@ -9,6 +9,7 @@ from flectra.tools import float_compare
|
||||
class StockScrap(models.Model):
|
||||
_name = 'stock.scrap'
|
||||
_order = 'id desc'
|
||||
_inherit = ['ir.branch.company.mixin']
|
||||
|
||||
def _get_default_scrap_location_id(self):
|
||||
return self.env['stock.location'].search([('scrap_location', '=', True)], limit=1).id
|
||||
@ -76,6 +77,11 @@ class StockScrap(models.Model):
|
||||
|
||||
def _prepare_move_values(self):
|
||||
self.ensure_one()
|
||||
branch_id = False
|
||||
if self.picking_id.branch_id:
|
||||
branch_id = self.picking_id.branch_id
|
||||
if not branch_id:
|
||||
branch_id = self.location_id.branch_id
|
||||
return {
|
||||
'name': self.name,
|
||||
'origin': self.origin or self.picking_id.name or self.name,
|
||||
@ -94,7 +100,8 @@ class StockScrap(models.Model):
|
||||
'owner_id': self.owner_id.id,
|
||||
'lot_id': self.lot_id.id, })],
|
||||
# 'restrict_partner_id': self.owner_id.id,
|
||||
'picking_id': self.picking_id.id
|
||||
'picking_id': self.picking_id.id,
|
||||
'branch_id': branch_id and branch_id.id
|
||||
}
|
||||
|
||||
@api.multi
|
||||
|
@ -69,6 +69,7 @@ class Warehouse(models.Model):
|
||||
default_resupply_wh_id = fields.Many2one(
|
||||
'stock.warehouse', 'Default Resupply Warehouse',
|
||||
help="Goods will always be resupplied from this warehouse")
|
||||
branch_id = fields.Many2one('res.branch', 'Branch', ondelete="restrict")
|
||||
|
||||
_sql_constraints = [
|
||||
('warehouse_name_uniq', 'unique(name, company_id)', 'The name of the warehouse must be unique per company!'),
|
||||
@ -80,6 +81,18 @@ class Warehouse(models.Model):
|
||||
# If we are removing the default resupply, we don't have default_resupply_wh_id # TDE note: and we want one
|
||||
self.resupply_wh_ids |= self.default_resupply_wh_id
|
||||
|
||||
@api.constrains('company_id', 'branch_id')
|
||||
def _check_company_branch(self):
|
||||
for record in self:
|
||||
if record.branch_id and record.company_id != record.branch_id.company_id:
|
||||
raise ValidationError(
|
||||
_('Configuration Error of Company:\n'
|
||||
'The Company (%s) in the Warehouse and '
|
||||
'the Company (%s) of Branch must '
|
||||
'be the same company!') % (record.company_id.name,
|
||||
record.branch_id.company_id.name)
|
||||
)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
# create view location for warehouse then create all locations
|
||||
@ -749,6 +762,9 @@ class Orderpoint(models.Model):
|
||||
location_id = fields.Many2one(
|
||||
'stock.location', 'Location',
|
||||
ondelete="cascade", required=True)
|
||||
branch_id = fields.Many2one('res.branch', 'Branch',
|
||||
related='location_id.branch_id', index=True,
|
||||
readonly=True, store=True)
|
||||
product_id = fields.Many2one(
|
||||
'product.product', 'Product',
|
||||
domain=[('type', '=', 'product')], ondelete='cascade', required=True)
|
||||
|
@ -31,6 +31,7 @@
|
||||
<th name="td_sched_date_h">
|
||||
<strong>Date</strong>
|
||||
</th>
|
||||
<th t-if="o.branch_id"><strong>Branch</strong></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -46,6 +47,9 @@
|
||||
<span t-field="o.scheduled_date"/>
|
||||
</t>
|
||||
</td>
|
||||
<td t-if="o.branch_id">
|
||||
<span t-field="o.branch_id"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -13,6 +13,7 @@
|
||||
<tr>
|
||||
<th><strong>Inventory</strong></th>
|
||||
<th><strong>Date</strong></th>
|
||||
<th t-if="o.branch_id"><strong>Branch</strong></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -23,6 +24,9 @@
|
||||
<td>
|
||||
<span t-field="o.date"/>
|
||||
</td>
|
||||
<td t-if="o.branch_id">
|
||||
<span t-field="o.branch_id"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -51,6 +51,7 @@
|
||||
<th><strong>State</strong></th>
|
||||
<th><strong>Commitment Date</strong></th>
|
||||
<th name="td_sched_date_h"><strong>Scheduled Date</strong></th>
|
||||
<th t-if="o.branch_id"><strong>Branch</strong></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@ -67,6 +68,9 @@
|
||||
<td name="td_sched_date">
|
||||
<span t-field="o.scheduled_date"/>
|
||||
</td>
|
||||
<td t-if="o.branch_id">
|
||||
<span t-field="o.branch_id"/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -156,5 +156,49 @@
|
||||
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
|
||||
</record>
|
||||
|
||||
<!-- Multi Branch rule -->
|
||||
<record id="location_multi_branch_rule" model="ir.rule">
|
||||
<field name="name">Locations multi-branch</field>
|
||||
<field name="model_id" ref="model_stock_location"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('branch_id', '=', False), '|', ('branch_id', '=', user.default_branch_id.id),
|
||||
('branch_id', 'in', user.branch_ids.ids)]
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--<record id="picking_type_multi_branch_rule" model="ir.rule">-->
|
||||
<!--<field name="name">Picking type multi-branch</field>-->
|
||||
<!--<field name="model_id" ref="model_stock_picking_type"/>-->
|
||||
<!--<field name="global" eval="True"/>-->
|
||||
<!--<field name="domain_force">['|',('warehouse_id.branch_id','=',False),('warehouse_id.branch_id','in',[branch for branch in user.branch_ids.ids])]-->
|
||||
<!--</field>-->
|
||||
<!--</record>-->
|
||||
|
||||
<record id="warehouse_multi_branch_rule" model="ir.rule">
|
||||
<field name="name">Warehouse multi-branch</field>
|
||||
<field name="model_id" ref="model_stock_warehouse"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('branch_id', '=', False), '|', ('branch_id', '=', user.default_branch_id.id),
|
||||
('branch_id', 'in', user.branch_ids.ids)]
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="picking_multi_branch_rule" model="ir.rule">
|
||||
<field name="name">Picking multi-branch</field>
|
||||
<field name="model_id" ref="model_stock_picking"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', ('branch_id', '=', False), '|', ('branch_id', '=', user.default_branch_id.id),
|
||||
('branch_id', 'in', user.branch_ids.ids)]
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="stock_move_multi_branch_rule" model="ir.rule">
|
||||
<field name="name">Stock Move multi-branch</field>
|
||||
<field name="model_id" ref="model_stock_move"/>
|
||||
<field name="global" eval="True"/>
|
||||
<field name="domain_force">['|', '|', ('location_id.branch_id','=',False),('location_id.branch_id','in',[branch for branch in user.branch_ids.ids]), ('location_id.branch_id','=',user.default_branch_id.id),
|
||||
'|', '|', ('location_dest_id.branch_id','=',False),('location_dest_id.branch_id','in',[branch for branch in user.branch_ids.ids]), ('location_dest_id.branch_id','=',user.default_branch_id.id)]
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</flectra>
|
||||
|
@ -9,3 +9,4 @@ from . import test_quant
|
||||
from . import test_inventory
|
||||
from . import test_move
|
||||
from . import test_move2
|
||||
from . import test_stock_branch
|
||||
|
@ -69,9 +69,11 @@ class TestStockCommon(common.TestProductCommon):
|
||||
'groups_id': [(6, 0, [user_group_stock_manager.id])]})
|
||||
|
||||
# Warehouses
|
||||
branch_id = cls.env.ref('base_branch_company.data_branch_1')
|
||||
cls.warehouse_1 = cls.env['stock.warehouse'].create({
|
||||
'name': 'Base Warehouse',
|
||||
'reception_steps': 'one_step',
|
||||
'branch_id': branch_id.id,
|
||||
'delivery_steps': 'ship_only',
|
||||
'code': 'BWH'})
|
||||
|
||||
|
@ -1468,8 +1468,9 @@ class TestSinglePicking(TestStockCommon):
|
||||
Move Input-> QC - Move QC -> Stock
|
||||
Move receipt 2 /
|
||||
"""
|
||||
branch_id = self.env.ref('base_branch_company.data_branch_1')
|
||||
warehouse = self.env['stock.warehouse'].create({
|
||||
'name': 'TEST WAREHOUSE',
|
||||
'name': 'TEST WAREHOUSE', 'branch_id': branch_id.id,
|
||||
'code': 'TEST1',
|
||||
'reception_steps': 'three_steps',
|
||||
})
|
||||
@ -1478,6 +1479,7 @@ class TestSinglePicking(TestStockCommon):
|
||||
'location_dest_id': warehouse.wh_input_stock_loc_id.id,
|
||||
'partner_id': self.partner_delta_id,
|
||||
'picking_type_id': warehouse.in_type_id.id,
|
||||
'branch_id': branch_id.id
|
||||
})
|
||||
move_receipt_1 = self.MoveObj.create({
|
||||
'name': self.productA.name,
|
||||
|
84
addons/stock/tests/test_stock_branch.py
Normal file
84
addons/stock/tests/test_stock_branch.py
Normal file
@ -0,0 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from flectra.addons.stock.tests import common
|
||||
|
||||
|
||||
class TestStockBranch(common.TestStockCommon):
|
||||
|
||||
def setUp(self):
|
||||
super(TestStockBranch, self).setUp()
|
||||
|
||||
self.branch_1 = self.env.ref('base_branch_company.data_branch_1')
|
||||
self.branch_2 = self.env.ref('base_branch_company.data_branch_2')
|
||||
self.main_company = self.env.ref('base.main_company')
|
||||
self.stock_manager_group = self.env.ref('stock.group_stock_manager')
|
||||
warehouse_wt = self.env.ref('stock.stock_warehouse_WW')
|
||||
|
||||
self.destination_loc_id = warehouse_wt.lot_stock_id.id
|
||||
self.picking_type_id = warehouse_wt.in_type_id
|
||||
|
||||
self.user_1 = self.create_stock_user(
|
||||
self.main_company, 'Test Stock User 1', self.branch_1,
|
||||
[self.branch_1, self.branch_2])
|
||||
self.user_2 = self.create_stock_user(
|
||||
self.main_company, 'Test Stock User 2', self.branch_2,
|
||||
[self.branch_2])
|
||||
self.picking_1 = self.pickings_create(
|
||||
self.picking_type_id, self.branch_2, self.user_1,
|
||||
self.supplier_location, self.stock_location)
|
||||
self.picking_2 = self.pickings_create(
|
||||
self.picking_type_id, self.branch_2, self.user_2,
|
||||
self.supplier_location, self.destination_loc_id)
|
||||
self.internal_picking = self.pickings_create(
|
||||
self.picking_type_id, self.branch_2, self.user_1,
|
||||
self.stock_location, self.destination_loc_id)
|
||||
|
||||
def pickings_create(self, picking_type_id, branch_id, user_id,
|
||||
source_loc_id, destination_loc_id):
|
||||
picking_id = self.PickingObj.sudo(user_id).create(
|
||||
{
|
||||
'location_id': source_loc_id,
|
||||
'picking_type_id': picking_type_id.id,
|
||||
'branch_id': branch_id.id,
|
||||
'location_dest_id': destination_loc_id,
|
||||
}
|
||||
)
|
||||
self.MoveObj.sudo(user_id).create(
|
||||
{
|
||||
'picking_id': picking_id.id,
|
||||
'product_uom_qty': 6.0,
|
||||
'name': 'Test Move of Picking',
|
||||
'location_id': source_loc_id,
|
||||
'location_dest_id': destination_loc_id,
|
||||
'product_id': self.productC.id,
|
||||
'product_uom': self.productC.uom_id.id,
|
||||
}
|
||||
)
|
||||
return picking_id
|
||||
|
||||
def create_stock_user(self, company_id, login_name, branch_id, branch_ids):
|
||||
user_obj = \
|
||||
self.env['res.users'].with_context(
|
||||
{'no_reset_password': True}).create(
|
||||
{
|
||||
'company_id': company_id.id,
|
||||
'default_branch_id': branch_id.id,
|
||||
'branch_ids': [(4, branch.id) for branch in branch_ids],
|
||||
'company_ids': [(4, company_id.id)],
|
||||
'login': login_name,
|
||||
'groups_id': [(6, 0, [self.stock_manager_group.id])],
|
||||
'name': 'Stock User ' + login_name,
|
||||
'email': 'demo@yourcompany.com',
|
||||
'password': '123'
|
||||
}
|
||||
)
|
||||
return user_obj.id
|
||||
|
||||
def test_stock_picking_branch(self):
|
||||
picking_ids = self.PickingObj.sudo(self.user_1).search([('id', '=', self.picking_1.id)]).ids
|
||||
self.assertNotEqual(picking_ids, [], '')
|
||||
|
||||
picking_ids = self.PickingObj.sudo(self.user_2).search([('id', '=', self.picking_2.id)]).ids
|
||||
self.assertNotEqual(picking_ids, [])
|
||||
|
||||
picking_ids = self.PickingObj.sudo(self.user_1).search([('id', '=', self.internal_picking.id)]).ids
|
||||
self.assertNotEqual(picking_ids, [])
|
@ -140,6 +140,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="location_id" domain="[('usage','not in', ['supplier','production'])]" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="filter" string="Inventory of" widget='radio' attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
</group>
|
||||
<group>
|
||||
|
@ -36,6 +36,7 @@
|
||||
<group string="Additional Information">
|
||||
<field name="usage"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="branch_id" options="{'no_create': True}"/>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
<field name="scrap_location"/>
|
||||
<field name="return_location"/>
|
||||
|
@ -12,7 +12,9 @@
|
||||
<field name="product_packaging" domain="[('product_id','=',product_id)]" groups="product.group_stock_packaging"/>
|
||||
<field name="picking_id"/>
|
||||
<field name="location_id" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="location_dest_id" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="branch_dest_id"/>
|
||||
<field name="create_date" groups="base.group_no_one"/>
|
||||
<field name="date" string="Date" groups="base.group_no_one"/>
|
||||
<field name="date_expected" string="Date Expected"/>
|
||||
@ -58,7 +60,9 @@
|
||||
<field name="create_date" invisible="1" groups="base.group_no_one"/>
|
||||
<field name="product_id"/>
|
||||
<field name="location_id" groups="stock.group_stock_multi_locations" string="From"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="location_dest_id" groups="stock.group_stock_multi_locations" string="To"/>
|
||||
<field name="branch_dest_id"/>
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="product_uom" options="{'no_open': True, 'no_create': True}" string="Unit of Measure" groups="product.group_uom"/>
|
||||
<field name="state"/>
|
||||
@ -112,6 +116,7 @@
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="product_uom" options="{'no_open': True, 'no_create': True}" string="Unit of Measure" groups="product.group_uom"/>
|
||||
<field name="location_id" invisible="1"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="create_date" invisible="1" />
|
||||
<field name="date_expected" invisible="1" />
|
||||
<field name="picking_type_id" invisible="1"/>
|
||||
@ -119,6 +124,7 @@
|
||||
<field name="availability" invisible="1"/>
|
||||
<field name="reserved_availability" invisible="1"/>
|
||||
<field name="location_dest_id" invisible="1"/>
|
||||
<field name="branch_dest_id"/>
|
||||
<field name="state"/>
|
||||
</tree>
|
||||
</field>
|
||||
@ -218,7 +224,9 @@
|
||||
<group name="main_grp_col1">
|
||||
<field name="reference"/>
|
||||
<field name="location_id"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="branch_dest_id"/>
|
||||
</group>
|
||||
<group name="main_grp_col2">
|
||||
<field name="product_id"/>
|
||||
|
@ -319,6 +319,7 @@
|
||||
</group>
|
||||
<group>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
<field name="branch_id" options="{'no_create': True}"/>
|
||||
<field name="group_id" groups="base.group_no_one"/>
|
||||
<field name="priority" attrs="{'invisible': [('picking_type_code', '=', 'incoming')]}"/>
|
||||
</group>
|
||||
|
@ -48,6 +48,7 @@
|
||||
<group>
|
||||
<field name="product_id"/>
|
||||
<field name="location_id"/>
|
||||
<field name="branch_id"/>
|
||||
<field name="lot_id" groups="stock.group_production_lot"/>
|
||||
<field name="package_id" groups="stock.group_tracking_lot"/>
|
||||
<field name="owner_id" groups="stock.group_tracking_owner"/>
|
||||
|
@ -52,6 +52,7 @@
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<field name="branch_id" />
|
||||
<field name="lot_id" attrs="{'invisible': [('tracking', '=', 'none')], 'required': [('tracking', '!=', 'none')]}" groups="stock.group_production_lot"/>
|
||||
<field name="tracking" invisible="1"/>
|
||||
<field name="package_id" groups="stock.group_tracking_lot"/>
|
||||
|
@ -26,6 +26,7 @@
|
||||
<group>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="branch_id" options="{'no_create': True}"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook colspan="4" groups="stock.group_adv_location">
|
||||
|
@ -376,6 +376,7 @@ class Users(models.Model):
|
||||
for id in self.ids:
|
||||
self.__uid_cache[db].pop(id, None)
|
||||
|
||||
self.clear_caches()
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
|
Loading…
Reference in New Issue
Block a user