[FIX]: Multi Branch : Purchase, Sale stock.

This commit is contained in:
Kunjal 2018-01-18 15:27:39 +05:30
parent 5993da4d2a
commit effce68e09
53 changed files with 698 additions and 43 deletions

View File

@ -5,27 +5,29 @@ from . import test_account_branch
class TestJournalEntryBranch(test_account_branch.TestAccountBranch): class TestJournalEntryBranch(test_account_branch.TestAccountBranch):
def test_journal_entries_branch(self): def test_journal_entries_branch(self):
journal_ids = self.model_account_journal.search([('code', '=', 'MISC')], self.sale_journal_id = \
limit=1) 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([]) move_vals = self.env['account.move'].default_get([])
lines = [ lines = [
(0, 0, { (0, 0, {
'name': 'Test', 'name': 'Test',
'account_id': self.asset_account.id, 'account_id': self.account_id.id,
'debit': 0, 'debit': 0,
'credit': 100, 'credit': 100,
'branch_id': self.branch_1.id, 'branch_id': self.branch_1.id,
}), }),
(0, 0, { (0, 0, {
'name': 'Test', 'name': 'Test',
'account_id': self.asset_account.id, 'account_id': self.account_id.id,
'debit': 100, 'debit': 100,
'credit': 0, 'credit': 0,
'branch_id': self.branch_1.id, 'branch_id': self.branch_1.id,
}) })
] ]
move_vals.update({ move_vals.update({
'journal_id': journal_ids and journal_ids.id, 'journal_id': self.sale_journal_id.id,
'line_ids': lines, 'line_ids': lines,
}) })
move = self.env['account.move'].sudo(self.user_id.id).create(move_vals) move = self.env['account.move'].sudo(self.user_id.id).create(move_vals)

View File

@ -23,6 +23,7 @@ Main Features
'website': '', 'website': '',
'depends': ['base'], 'depends': ['base'],
'data': [ 'data': [
'demo/branch_data.xml',
'security/branch_security.xml', 'security/branch_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'views/res_branch_view.xml', 'views/res_branch_view.xml',

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

View File

@ -2,8 +2,7 @@
<flectra> <flectra>
<data noupdate="1"> <data noupdate="1">
<record id="data_branch_4" model="res.branch">
<record id="data_branch_1" model="res.branch">
<field name="name">New York</field> <field name="name">New York</field>
<field name="code">NY</field> <field name="code">NY</field>
<field name="company_id" ref="base.main_company"/> <field name="company_id" ref="base.main_company"/>
@ -34,10 +33,7 @@
<field name='state_id' ref='base.state_us_48'/> <field name='state_id' ref='base.state_us_48'/>
<field name="phone">(372) 587-2335</field> <field name="phone">(372) 587-2335</field>
</record> </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"> <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')])]"/> <field name="branch_ids" eval="[(6,0,[ref('data_branch_1'),ref('data_branch_2'),ref('data_branch_3')])]"/>

View File

@ -88,18 +88,34 @@ class Users(models.Model):
self.env['res.users'].browse(user).company_id.branch_id self.env['res.users'].browse(user).company_id.branch_id
return branch_id return branch_id
@api.model
def _get_branch(self):
return self.env.user.default_branch_id
@api.model @api.model
def _get_default_branch(self): def _get_default_branch(self):
return self.branch_default_get(self._uid) 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', branch_ids = fields.Many2many('res.branch',
'res_branch_users_rel', 'res_branch_users_rel',
'user_id', 'user_id',
'branch_id', 'branch_id',
'Branches') 'Branches', default=_get_branch,
domain="[('company_id','=',company_id)]")
default_branch_id = fields.Many2one('res.branch', 'Default branch', default_branch_id = fields.Many2one('res.branch', 'Default branch',
default=_get_default_branch, default=_get_branch,
domain="[('company_id','=',company_id)" 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

View File

@ -87,16 +87,12 @@
<field name="model">res.users</field> <field name="model">res.users</field>
<field name="inherit_id" ref="base.view_users_form"/> <field name="inherit_id" ref="base.view_users_form"/>
<field name="arch" type="xml"> <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>
<group string="Multi Companies" attrs="{'invisible': [('companies_count', '&lt;=', 1)]}"> <group string="Allowed Branches" attrs="{'invisible': [('branches_count', '&lt;=', 1)]}">
<field string="Allowed Companies" name="company_ids" widget="many2many_tags"/> <field name="default_branch_id"/>
<field string="Current Company" name="company_id" context="{'user_preference': 0}"/> <field name="branch_ids" widget="many2many_tags"/>
<field string="Companies count" name="companies_count" invisible="1"/> <field string="Branches count" name="branches_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> </group>
</group> </group>
</xpath> </xpath>

View File

@ -78,7 +78,7 @@ class Team(models.Model):
values['alias_defaults'] = defaults = safe_eval(self.alias_defaults or "{}") 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['type'] = 'lead' if has_group_use_lead and self.use_leads else 'opportunity'
defaults['team_id'] = self.id 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 return values
@api.onchange('use_leads', 'use_opportunities') @api.onchange('use_leads', 'use_opportunities')

View File

@ -16,13 +16,13 @@ class TestTimesheet(TransactionCase):
}) })
self.task1 = self.env['project.task'].create({ self.task1 = self.env['project.task'].create({
'name': 'Task One', 'name': 'Task One',
'priority': '0', 'priority': 'l',
'kanban_state': 'normal', 'kanban_state': 'normal',
'project_id': self.project_customer.id, 'project_id': self.project_customer.id,
}) })
self.task2 = self.env['project.task'].create({ self.task2 = self.env['project.task'].create({
'name': 'Task Two', 'name': 'Task Two',
'priority': '1', 'priority': 'm',
'kanban_state': 'done', 'kanban_state': 'done',
'project_id': self.project_customer.id, 'project_id': self.project_customer.id,
}) })

View File

@ -12,6 +12,7 @@
product_qty: 15.0 product_qty: 15.0
product_uom: product.product_uom_unit product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d') 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}: !record {model: purchase.order.line, id: purchase_order_line_2}:
order_id: purchase_order_1 order_id: purchase_order_1
@ -21,6 +22,7 @@
product_qty: 5.0 product_qty: 5.0
product_uom: product.product_uom_unit product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d') 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}: !record {model: purchase.order.line, id: purchase_order_line_3}:
order_id: purchase_order_1 order_id: purchase_order_1
@ -30,11 +32,13 @@
product_qty: 4.0 product_qty: 4.0
product_uom: product.product_uom_unit product_uom: product.product_uom_unit
date_planned: !eval time.strftime('%Y-%m-%d') date_planned: !eval time.strftime('%Y-%m-%d')
branch_id: base_branch_company.data_branch_2
- -
Creating second order Creating second order
- -
!record {model: purchase.order, id: purchase_order_2}: !record {model: purchase.order, id: purchase_order_2}:
partner_id: base.res_partner_3 partner_id: base.res_partner_3
branch_id: base_branch_company.data_branch_1
order_line: order_line:
- product_id: product.product_delivery_02 - product_id: product.product_delivery_02
name: Multimedia Speakers name: Multimedia Speakers
@ -52,6 +56,7 @@
- -
!record {model: purchase.order, id: purchase_order_3}: !record {model: purchase.order, id: purchase_order_3}:
partner_id: base.res_partner_12 partner_id: base.res_partner_12
branch_id: base_branch_company.data_branch_1
order_line: order_line:
- product_id: product.product_product_2 - product_id: product.product_product_2
name: Support Services name: Support Services
@ -63,6 +68,7 @@
- -
!record {model: purchase.order, id: purchase_order_4}: !record {model: purchase.order, id: purchase_order_4}:
partner_id: base.res_partner_4 partner_id: base.res_partner_4
branch_id: base_branch_company.data_branch_1
order_line: order_line:
- product_id: product.product_delivery_02 - product_id: product.product_delivery_02
name: RAM SR2 (kit) name: RAM SR2 (kit)
@ -86,6 +92,7 @@
- -
!record {model: purchase.order, id: purchase_order_5}: !record {model: purchase.order, id: purchase_order_5}:
partner_id: base.res_partner_2 partner_id: base.res_partner_2
branch_id: base_branch_company.data_branch_1
order_line: order_line:
- product_id: product.product_product_22 - product_id: product.product_product_22
name: Processor Core i5 2.70 Ghz name: Processor Core i5 2.70 Ghz

View File

@ -7,7 +7,7 @@ from dateutil.relativedelta import relativedelta
from flectra import api, fields, models, SUPERUSER_ID, _ from flectra import api, fields, models, SUPERUSER_ID, _
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT
from flectra.tools.float_utils import float_is_zero, float_compare 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.tools.misc import formatLang
from flectra.addons.base.res.res_partner import WARNING_MESSAGE, WARNING_HELP from flectra.addons.base.res.res_partner import WARNING_MESSAGE, WARNING_HELP
from flectra.addons import decimal_precision as dp from flectra.addons import decimal_precision as dp
@ -15,7 +15,7 @@ from flectra.addons import decimal_precision as dp
class PurchaseOrder(models.Model): class PurchaseOrder(models.Model):
_name = "purchase.order" _name = "purchase.order"
_inherit = ['mail.thread', 'mail.activity.mixin'] _inherit = ['mail.thread', 'mail.activity.mixin', 'ir.branch.company.mixin']
_description = "Purchase Order" _description = "Purchase Order"
_order = 'date_order desc, id desc' _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]): if order.picking_ids and all([x.state == 'done' for x in order.picking_ids]):
order.is_shipped = True 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 = { READONLY_STATES = {
'purchase': [('readonly', True)], 'purchase': [('readonly', True)],
'done': [('readonly', True)], 'done': [('readonly', True)],
@ -493,7 +518,11 @@ class PurchaseOrder(models.Model):
result = action.read()[0] result = action.read()[0]
#override the context to get rid of the default filtering #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: if not self.invoice_ids:
# Choose a default account journal in the same currency in case a new invoice is created # 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') orderpoint_id = fields.Many2one('stock.warehouse.orderpoint', 'Orderpoint')
move_dest_ids = fields.One2many('stock.move', 'created_purchase_line_id', 'Downstream Moves') 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 @api.multi
def _create_or_update_picking(self): def _create_or_update_picking(self):

View File

@ -42,6 +42,10 @@
<strong>Order Date:</strong> <strong>Order Date:</strong>
<p t-field="o.date_order"/> <p t-field="o.date_order"/>
</div> </div>
<div name="branch" t-if="o.branch_id" class="col-xs-3">
<strong>Branch:</strong>
<p t-field="o.branch_id"/>
</div>
</div> </div>
<table class="table table-condensed"> <table class="table table-condensed">

View File

@ -26,6 +26,13 @@
</div> </div>
</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> <h2>Request for Quotation <span t-field="o.name"/></h2>
<table class="table table-condensed"> <table class="table table-condensed">

View File

@ -10,6 +10,7 @@ from flectra import api, fields, models, tools
class PurchaseReport(models.Model): class PurchaseReport(models.Model):
_name = "purchase.report" _name = "purchase.report"
_inherit = ['ir.branch.company.mixin']
_description = "Purchases Orders" _description = "Purchases Orders"
_auto = False _auto = False
_order = 'date_order desc, price_total desc' _order = 'date_order desc, price_total desc'
@ -64,6 +65,7 @@ class PurchaseReport(models.Model):
s.partner_id as partner_id, s.partner_id as partner_id,
s.create_uid as user_id, s.create_uid as user_id,
s.company_id as company_id, s.company_id as company_id,
s.branch_id as branch_id,
s.fiscal_position_id as fiscal_position_id, s.fiscal_position_id as fiscal_position_id,
l.product_id, l.product_id,
p.product_tmpl_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()))) (cr.date_end is null or cr.date_end > coalesce(s.date_order, now())))
group by group by
s.company_id, s.company_id,
s.branch_id,
s.create_uid, s.create_uid,
s.partner_id, s.partner_id,
u.factor, u.factor,

View File

@ -75,5 +75,30 @@
<field name="domain_force">[('order_id.message_partner_ids','child_of',[user.commercial_partner_id.id])]</field> <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'))]"/> <field name="groups" eval="[(4, ref('base.group_portal'))]"/>
</record> </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> </data>
</flectra> </flectra>

View File

@ -6,3 +6,5 @@ from . import test_purchase_order
from . import test_create_picking from . import test_create_picking
from . import test_purchase_lead_time from . import test_purchase_lead_time
from . import test_stockvaluation from . import test_stockvaluation
from . import test_purchase_branch
from . import test_user_authorization

View 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

View File

@ -13,6 +13,9 @@ class TestPurchaseLeadTime(TestPurchase):
""" To check dates, set product's Delivery Lead Time """ To check dates, set product's Delivery Lead Time
and company's Purchase 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') company = self.env.ref('base.main_company')
# Update company with Purchase Lead Time # Update company with Purchase Lead Time
@ -49,6 +52,9 @@ class TestPurchaseLeadTime(TestPurchase):
and different Delivery Lead Time.""" and different Delivery Lead Time."""
# Make procurement request from product_1's form view, create procurement and check it's state # 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)) 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) 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 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.""" and warehouse route's delay."""
# Update warehouse_1 with Incoming Shipments 3 steps # 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'}) self.warehouse_1.write({'reception_steps': 'three_steps'})
# Set delay on push rule # Set delay on push rule

View File

@ -2,7 +2,7 @@
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details. # Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from datetime import datetime from datetime import datetime
import time
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT
from flectra.addons.account.tests.account_test_classes import AccountingTestCase 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.partner_id = self.env.ref('base.res_partner_1')
self.product_id_1 = self.env.ref('product.product_product_8') 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_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.product_id_1 | self.product_id_2).write({'purchase_method': 'purchase'})
self.po_vals = { self.po_vals = {

View 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)))

View File

@ -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="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="default_location_dest_id_usage" invisible="1"/>
<field name="incoterm_id"/> <field name="incoterm_id"/>
<field name="branch_id" options="{'no_create': True, 'no_create_edit': True}"/>
</group> </group>
<group> <group>
<field name="invoice_status"/> <field name="invoice_status"/>
@ -336,6 +337,7 @@
<filter string="Vendor" domain="[]" context="{'group_by':'partner_id'}"/> <filter string="Vendor" domain="[]" context="{'group_by':'partner_id'}"/>
<filter string="Order Date" domain="[]" context="{'group_by':'date_order'}"/> <filter string="Order Date" domain="[]" context="{'group_by':'date_order'}"/>
<filter string="Expected Date" domain="[]" context="{'group_by':'date_planned'}"/> <filter string="Expected Date" domain="[]" context="{'group_by':'date_planned'}"/>
<filter name="groupby_branch" string="Branch" domain="[]" context="{'group_by': 'branch_id'}"/>
</group> </group>
</search> </search>
</field> </field>
@ -388,6 +390,7 @@
<field name="date_order" /> <field name="date_order" />
<field name="partner_id"/> <field name="partner_id"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/> <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="date_planned" invisible="context.get('quotation_only', False)"/>
<field name="origin"/> <field name="origin"/>
<field name="amount_untaxed" sum="Total Untaxed amount" string="Untaxed" widget="monetary"/> <field name="amount_untaxed" sum="Total Untaxed amount" string="Untaxed" widget="monetary"/>

View File

@ -6,7 +6,6 @@ from flectra import api, fields, models, tools
class PosSaleReport(models.Model): class PosSaleReport(models.Model):
_name = "report.all.channels.sales" _name = "report.all.channels.sales"
_inherit = ['ir.branch.company.mixin']
_description = "All sales orders grouped by sales channels" _description = "All sales orders grouped by sales channels"
_auto = False _auto = False
@ -38,7 +37,6 @@ class PosSaleReport(models.Model):
so.user_id AS user_id, so.user_id AS user_id,
pt.categ_id AS categ_id, pt.categ_id AS categ_id,
so.company_id AS company_id, so.company_id AS company_id,
so.branch_id AS branch_id,
sol.price_total / COALESCE(cr.rate, 1.0) AS price_total, sol.price_total / COALESCE(cr.rate, 1.0) AS price_total,
so.pricelist_id AS pricelist_id, so.pricelist_id AS pricelist_id,
rp.country_id AS country_id, rp.country_id AS country_id,
@ -77,7 +75,6 @@ class PosSaleReport(models.Model):
user_id, user_id,
categ_id, categ_id,
company_id, company_id,
branch_id,
price_total, price_total,
pricelist_id, pricelist_id,
analytic_account_id, analytic_account_id,

View File

@ -12,17 +12,49 @@ class TestSaleBranch(common.TransactionCase):
self.payment_model_obj = self.env['sale.advance.payment.inv'] 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.sale_user_group = self.env.ref('sales_team.group_sale_manager')
self.account_user_group = self.env.ref('account.group_account_invoice') 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_1 = self.env.ref('base_branch_company.data_branch_1')
self.branch_2 = self.env.ref('base_branch_company.data_branch_2') 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.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.user_1 = self.create_sale_user(
self.main_company, 'user_1', self.branch_1, self.main_company, 'user_1', self.branch_1,

View File

@ -5,7 +5,7 @@ from datetime import datetime, timedelta
from flectra import api, fields, models, _ from flectra import api, fields, models, _
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_compare 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): class SaleOrder(models.Model):

View File

@ -133,6 +133,7 @@
<field model="res.company" name="name" search="[]" use="name"/> <field model="res.company" name="name" search="[]" use="name"/>
<field name="partner_id" ref="base.main_partner"/> <field name="partner_id" ref="base.main_partner"/>
<field name="code">WH</field> <field name="code">WH</field>
<field name="branch_id" ref="base_branch_company.data_branch_1"/>
</record> </record>
<record id="sequence_mrp_op" model="ir.sequence"> <record id="sequence_mrp_op" model="ir.sequence">

View File

@ -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}: | !python {model: res.partner, id: base.main_partner}: |
main_warehouse = self.env['stock.warehouse'].browse(ref('warehouse0')) main_warehouse = self.env['stock.warehouse'].browse(ref('warehouse0'))
@ -30,4 +36,15 @@
companies = self.search([('internal_transit_location_id', '=', False)]) companies = self.search([('internal_transit_location_id', '=', False)])
for company in companies: for company in companies:
company.create_transit_location() 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})

View File

@ -167,13 +167,49 @@
<field name="name">My Company, Chicago</field> <field name="name">My Company, Chicago</field>
</record> </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"> <record id="stock_warehouse_shop0" model="stock.warehouse">
<field name="name">Chicago Warehouse</field> <field name="name">Chicago Warehouse</field>
<field name="partner_id" ref="res_partner_address_41"/> <field name="partner_id" ref="res_partner_address_41"/>
<field name="company_id" ref="res_company_1"/> <field name="company_id" ref="res_company_1"/>
<field name="branch_id" ref="branch_shop0"/>
<field name="code">Chic</field> <field name="code">Chic</field>
</record> </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> </data>
</flectra> </flectra>

View File

@ -14,10 +14,18 @@
self.create(xml_record) self.create(xml_record)
#avoid the xml id and the associated resource being dropped by the orm by manually making a hit on it #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']) 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}: !record {model: stock.location, id: location_refrigerator_small}:
name: Small Refrigerator name: Small Refrigerator
usage: internal usage: internal
branch_id: base_branch_company.data_branch_1
location_id: stock_location_14 location_id: stock_location_14
- -
!record {model: product.product, id: product_icecream}: !record {model: product.product, id: product_icecream}:
@ -201,6 +209,8 @@
picking_type_id: chi_picking_type_in picking_type_id: chi_picking_type_in
origin: 'incoming_chicago_warehouse' origin: 'incoming_chicago_warehouse'
partner_id: base.res_partner_1 partner_id: base.res_partner_1
company_id: stock.res_company_1
branch_id: stock.branch_shop0
location_id: stock.stock_location_suppliers location_id: stock.stock_location_suppliers
location_dest_id: stock.stock_location_shop0 location_dest_id: stock.stock_location_shop0
move_lines: move_lines:
@ -215,7 +225,9 @@
!record {model: stock.picking, id: incomming_chicago_warehouse1}: !record {model: stock.picking, id: incomming_chicago_warehouse1}:
picking_type_id: chi_picking_type_in picking_type_id: chi_picking_type_in
partner_id: base.res_partner_1 partner_id: base.res_partner_1
branch_id: stock.branch_shop0
location_id: stock.stock_location_suppliers location_id: stock.stock_location_suppliers
company_id: stock.res_company_1
location_dest_id: stock.stock_location_shop0 location_dest_id: stock.stock_location_shop0
move_lines: move_lines:
- product_id: product.product_delivery_01 - product_id: product.product_delivery_01
@ -235,6 +247,8 @@
!record {model: stock.picking, id: incomming_chicago_warehouse2}: !record {model: stock.picking, id: incomming_chicago_warehouse2}:
picking_type_id: chi_picking_type_in picking_type_id: chi_picking_type_in
partner_id: base.res_partner_1 partner_id: base.res_partner_1
branch_id: stock.branch_shop0
company_id: stock.res_company_1
location_id: stock.stock_location_suppliers location_id: stock.stock_location_suppliers
location_dest_id: stock.stock_location_shop0 location_dest_id: stock.stock_location_shop0
move_lines: move_lines:
@ -247,6 +261,8 @@
- -
!record {model: stock.picking, id: incomming_chicago_warehouse3}: !record {model: stock.picking, id: incomming_chicago_warehouse3}:
picking_type_id: chi_picking_type_in picking_type_id: chi_picking_type_in
branch_id: stock.branch_shop0
company_id: stock.res_company_1
origin: 'chicago_warehouse' origin: 'chicago_warehouse'
partner_id: base.res_partner_1 partner_id: base.res_partner_1
date: !eval "'%s-%s-2' % ((datetime.now()-timedelta(days=30)).month,(datetime.now()-timedelta(days=30)).month)" 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}: !record {model: stock.picking, id: outgoing_chicago_warehouse}:
picking_type_id: chi_picking_type_out picking_type_id: chi_picking_type_out
origin: 'outgoing_chicago_warehouse' origin: 'outgoing_chicago_warehouse'
branch_id: stock.branch_shop0
company_id: stock.res_company_1
partner_id: base.res_partner_1 partner_id: base.res_partner_1
location_id: stock.stock_location_shop0 location_id: stock.stock_location_shop0
location_dest_id: stock.stock_location_customers location_dest_id: stock.stock_location_customers
@ -279,6 +297,8 @@
!record {model: stock.picking, id: outgoing_chicago_warehouse1}: !record {model: stock.picking, id: outgoing_chicago_warehouse1}:
picking_type_id: chi_picking_type_out picking_type_id: chi_picking_type_out
origin: 'outgoing_shipment_chicago_warehouse' origin: 'outgoing_shipment_chicago_warehouse'
company_id: stock.res_company_1
branch_id: stock.branch_shop0
partner_id: base.res_partner_1 partner_id: base.res_partner_1
location_id: stock.stock_location_shop0 location_id: stock.stock_location_shop0
location_dest_id: stock.stock_location_customers location_dest_id: stock.stock_location_customers
@ -299,6 +319,8 @@
!record {model: stock.picking, id: outgoing_chicago_warehouse2}: !record {model: stock.picking, id: outgoing_chicago_warehouse2}:
picking_type_id: chi_picking_type_out picking_type_id: chi_picking_type_out
origin: 'chicago_warehouse' origin: 'chicago_warehouse'
company_id: stock.res_company_1
branch_id: stock.branch_shop0
partner_id: base.res_partner_1 partner_id: base.res_partner_1
location_id: stock.stock_location_shop0 location_id: stock.stock_location_shop0
location_dest_id: stock.stock_location_customers location_dest_id: stock.stock_location_customers
@ -312,6 +334,8 @@
- -
!record {model: stock.picking, id: outgoing_chicago_warehouse3}: !record {model: stock.picking, id: outgoing_chicago_warehouse3}:
picking_type_id: chi_picking_type_out picking_type_id: chi_picking_type_out
company_id: stock.res_company_1
branch_id: stock.branch_shop0
origin: 'outgoing chicago warehouse' origin: 'outgoing chicago warehouse'
location_id: stock.stock_location_shop0 location_id: stock.stock_location_shop0
location_dest_id: stock.stock_location_customers location_dest_id: stock.stock_location_customers

View File

@ -1,11 +1,13 @@
- -
!record {model: stock.location, id: stock_location_14}: !record {model: stock.location, id: stock_location_14}:
name: Shelf 2 name: Shelf 2
branch_id: base_branch_company.data_branch_1
posx: 0 posx: 0
- -
!record {model: stock.location, id: stock_location_components}: !record {model: stock.location, id: stock_location_components}:
name: Shelf 1 name: Shelf 1
branch_id: base_branch_company.data_branch_1
posx: 0 posx: 0
- -

View File

@ -2,19 +2,23 @@
!record {model: stock.location, id: location_order}: !record {model: stock.location, id: location_order}:
name: Order Processing name: Order Processing
usage: internal usage: internal
branch_id: base_branch_company.data_branch_1
location_id: stock.stock_location_company location_id: stock.stock_location_company
- -
!record {model: stock.location, id: location_dispatch_zone}: !record {model: stock.location, id: location_dispatch_zone}:
name: Dispatch Zone name: Dispatch Zone
branch_id: base_branch_company.data_branch_1
usage: internal usage: internal
location_id: location_order location_id: location_order
- -
!record {model: stock.location, id: location_gate_a}: !record {model: stock.location, id: location_gate_a}:
name: Gate A name: Gate A
usage: internal usage: internal
branch_id: base_branch_company.data_branch_1
location_id: location_dispatch_zone location_id: location_dispatch_zone
- -
!record {model: stock.location, id: location_gate_b}: !record {model: stock.location, id: location_gate_b}:
name: Gate B name: Gate B
branch_id: base_branch_company.data_branch_1
usage: internal usage: internal
location_id: location_dispatch_zone location_id: location_dispatch_zone

View File

@ -34,6 +34,12 @@ class Company(models.Model):
# multi-company rules prevents creating warehouse and sub-locations # multi-company rules prevents creating warehouse and sub-locations
self.env['stock.warehouse'].check_access_rights('create') 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() company.create_transit_location()
return company return company

View File

@ -54,6 +54,10 @@ class Inventory(models.Model):
readonly=True, required=True, readonly=True, required=True,
states={'draft': [('readonly', False)]}, states={'draft': [('readonly', False)]},
default=_default_location_id) 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_id = fields.Many2one(
'product.product', 'Inventoried Product', 'product.product', 'Inventoried Product',
readonly=True, readonly=True,
@ -295,6 +299,9 @@ class InventoryLine(models.Model):
inventory_id = fields.Many2one( inventory_id = fields.Many2one(
'stock.inventory', 'Inventory', 'stock.inventory', 'Inventory',
index=True, ondelete='cascade') 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') partner_id = fields.Many2one('res.partner', 'Owner')
product_id = fields.Many2one( product_id = fields.Many2one(
'product.product', 'Product', 'product.product', 'Product',

View File

@ -3,7 +3,7 @@
from datetime import datetime from datetime import datetime
from dateutil import relativedelta from dateutil import relativedelta
from flectra.exceptions import UserError from flectra.exceptions import UserError, ValidationError
from flectra import api, fields, models, _ from flectra import api, fields, models, _
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT 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.") 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.") 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') 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') 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 !')] _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.")) raise UserError(_("This location's usage cannot be changed to view as it contains products."))
return super(Location, self).write(values) 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): def name_get(self):
ret_list = [] ret_list = []
for location in self: for location in self:

View File

@ -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_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') 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) 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') @api.depends('picking_id.is_locked')
def _compute_is_locked(self): def _compute_is_locked(self):

View File

@ -9,7 +9,7 @@ from itertools import groupby
from flectra import api, fields, models, _ from flectra import api, fields, models, _
from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT from flectra.tools import DEFAULT_SERVER_DATETIME_FORMAT
from flectra.tools.float_utils import float_compare, float_round 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 flectra.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES
from operator import itemgetter from operator import itemgetter
@ -263,6 +263,11 @@ class Picking(models.Model):
index=True, required=True, index=True, required=True,
states={'done': [('readonly', True)], 'cancel': [('readonly', 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_ids = fields.One2many('stock.move.line', 'picking_id', 'Operations')
move_line_exist = fields.Boolean( 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!'), ('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') @api.depends('picking_type_id.show_operations')
def _compute_show_operations(self): def _compute_show_operations(self):
for picking in self: for picking in self:
@ -873,7 +903,9 @@ class Picking(models.Model):
'res_model': 'stock.scrap', 'res_model': 'stock.scrap',
'view_id': self.env.ref('stock.stock_scrap_form_view2').id, 'view_id': self.env.ref('stock.stock_scrap_form_view2').id,
'type': 'ir.actions.act_window', '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', 'target': 'new',
} }

View File

@ -33,6 +33,8 @@ class StockQuant(models.Model):
location_id = fields.Many2one( location_id = fields.Many2one(
'stock.location', 'Location', 'stock.location', 'Location',
auto_join=True, ondelete='restrict', readonly=True, required=True) auto_join=True, ondelete='restrict', readonly=True, required=True)
branch_id = fields.Many2one(related='location_id.branch_id',
string='Branch', )
lot_id = fields.Many2one( lot_id = fields.Many2one(
'stock.production.lot', 'Lot/Serial Number', 'stock.production.lot', 'Lot/Serial Number',
ondelete='restrict', readonly=True) ondelete='restrict', readonly=True)

View File

@ -9,6 +9,7 @@ from flectra.tools import float_compare
class StockScrap(models.Model): class StockScrap(models.Model):
_name = 'stock.scrap' _name = 'stock.scrap'
_order = 'id desc' _order = 'id desc'
_inherit = ['ir.branch.company.mixin']
def _get_default_scrap_location_id(self): def _get_default_scrap_location_id(self):
return self.env['stock.location'].search([('scrap_location', '=', True)], limit=1).id 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): def _prepare_move_values(self):
self.ensure_one() 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 { return {
'name': self.name, 'name': self.name,
'origin': self.origin or self.picking_id.name or 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, 'owner_id': self.owner_id.id,
'lot_id': self.lot_id.id, })], 'lot_id': self.lot_id.id, })],
# 'restrict_partner_id': self.owner_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 @api.multi

View File

@ -69,6 +69,7 @@ class Warehouse(models.Model):
default_resupply_wh_id = fields.Many2one( default_resupply_wh_id = fields.Many2one(
'stock.warehouse', 'Default Resupply Warehouse', 'stock.warehouse', 'Default Resupply Warehouse',
help="Goods will always be resupplied from this warehouse") help="Goods will always be resupplied from this warehouse")
branch_id = fields.Many2one('res.branch', 'Branch', ondelete="restrict")
_sql_constraints = [ _sql_constraints = [
('warehouse_name_uniq', 'unique(name, company_id)', 'The name of the warehouse must be unique per company!'), ('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 # 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 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 @api.model
def create(self, vals): def create(self, vals):
# create view location for warehouse then create all locations # create view location for warehouse then create all locations
@ -749,6 +762,9 @@ class Orderpoint(models.Model):
location_id = fields.Many2one( location_id = fields.Many2one(
'stock.location', 'Location', 'stock.location', 'Location',
ondelete="cascade", required=True) 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_id = fields.Many2one(
'product.product', 'Product', 'product.product', 'Product',
domain=[('type', '=', 'product')], ondelete='cascade', required=True) domain=[('type', '=', 'product')], ondelete='cascade', required=True)

View File

@ -31,6 +31,7 @@
<th name="td_sched_date_h"> <th name="td_sched_date_h">
<strong>Date</strong> <strong>Date</strong>
</th> </th>
<th t-if="o.branch_id"><strong>Branch</strong></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -46,6 +47,9 @@
<span t-field="o.scheduled_date"/> <span t-field="o.scheduled_date"/>
</t> </t>
</td> </td>
<td t-if="o.branch_id">
<span t-field="o.branch_id"/>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -13,6 +13,7 @@
<tr> <tr>
<th><strong>Inventory</strong></th> <th><strong>Inventory</strong></th>
<th><strong>Date</strong></th> <th><strong>Date</strong></th>
<th t-if="o.branch_id"><strong>Branch</strong></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -23,6 +24,9 @@
<td> <td>
<span t-field="o.date"/> <span t-field="o.date"/>
</td> </td>
<td t-if="o.branch_id">
<span t-field="o.branch_id"/>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -51,6 +51,7 @@
<th><strong>State</strong></th> <th><strong>State</strong></th>
<th><strong>Commitment Date</strong></th> <th><strong>Commitment Date</strong></th>
<th name="td_sched_date_h"><strong>Scheduled 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> </tr>
</thead> </thead>
<tbody> <tbody>
@ -67,6 +68,9 @@
<td name="td_sched_date"> <td name="td_sched_date">
<span t-field="o.scheduled_date"/> <span t-field="o.scheduled_date"/>
</td> </td>
<td t-if="o.branch_id">
<span t-field="o.branch_id"/>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -156,5 +156,49 @@
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field> <field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record> </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> </data>
</flectra> </flectra>

View File

@ -9,3 +9,4 @@ from . import test_quant
from . import test_inventory from . import test_inventory
from . import test_move from . import test_move
from . import test_move2 from . import test_move2
from . import test_stock_branch

View File

@ -69,9 +69,11 @@ class TestStockCommon(common.TestProductCommon):
'groups_id': [(6, 0, [user_group_stock_manager.id])]}) 'groups_id': [(6, 0, [user_group_stock_manager.id])]})
# Warehouses # Warehouses
branch_id = cls.env.ref('base_branch_company.data_branch_1')
cls.warehouse_1 = cls.env['stock.warehouse'].create({ cls.warehouse_1 = cls.env['stock.warehouse'].create({
'name': 'Base Warehouse', 'name': 'Base Warehouse',
'reception_steps': 'one_step', 'reception_steps': 'one_step',
'branch_id': branch_id.id,
'delivery_steps': 'ship_only', 'delivery_steps': 'ship_only',
'code': 'BWH'}) 'code': 'BWH'})

View File

@ -1468,8 +1468,9 @@ class TestSinglePicking(TestStockCommon):
Move Input-> QC - Move QC -> Stock Move Input-> QC - Move QC -> Stock
Move receipt 2 / Move receipt 2 /
""" """
branch_id = self.env.ref('base_branch_company.data_branch_1')
warehouse = self.env['stock.warehouse'].create({ warehouse = self.env['stock.warehouse'].create({
'name': 'TEST WAREHOUSE', 'name': 'TEST WAREHOUSE', 'branch_id': branch_id.id,
'code': 'TEST1', 'code': 'TEST1',
'reception_steps': 'three_steps', 'reception_steps': 'three_steps',
}) })
@ -1478,6 +1479,7 @@ class TestSinglePicking(TestStockCommon):
'location_dest_id': warehouse.wh_input_stock_loc_id.id, 'location_dest_id': warehouse.wh_input_stock_loc_id.id,
'partner_id': self.partner_delta_id, 'partner_id': self.partner_delta_id,
'picking_type_id': warehouse.in_type_id.id, 'picking_type_id': warehouse.in_type_id.id,
'branch_id': branch_id.id
}) })
move_receipt_1 = self.MoveObj.create({ move_receipt_1 = self.MoveObj.create({
'name': self.productA.name, 'name': self.productA.name,

View 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, [])

View File

@ -140,6 +140,7 @@
<group> <group>
<group> <group>
<field name="location_id" domain="[('usage','not in', ['supplier','production'])]" groups="stock.group_stock_multi_locations"/> <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')]}"/> <field name="filter" string="Inventory of" widget='radio' attrs="{'readonly': [('state', '!=', 'draft')]}"/>
</group> </group>
<group> <group>

View File

@ -36,6 +36,7 @@
<group string="Additional Information"> <group string="Additional Information">
<field name="usage"/> <field name="usage"/>
<field name="partner_id"/> <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="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
<field name="scrap_location"/> <field name="scrap_location"/>
<field name="return_location"/> <field name="return_location"/>

View File

@ -12,7 +12,9 @@
<field name="product_packaging" domain="[('product_id','=',product_id)]" groups="product.group_stock_packaging"/> <field name="product_packaging" domain="[('product_id','=',product_id)]" groups="product.group_stock_packaging"/>
<field name="picking_id"/> <field name="picking_id"/>
<field name="location_id" groups="stock.group_stock_multi_locations"/> <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="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="create_date" groups="base.group_no_one"/>
<field name="date" string="Date" groups="base.group_no_one"/> <field name="date" string="Date" groups="base.group_no_one"/>
<field name="date_expected" string="Date Expected"/> <field name="date_expected" string="Date Expected"/>
@ -58,7 +60,9 @@
<field name="create_date" invisible="1" groups="base.group_no_one"/> <field name="create_date" invisible="1" groups="base.group_no_one"/>
<field name="product_id"/> <field name="product_id"/>
<field name="location_id" groups="stock.group_stock_multi_locations" string="From"/> <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="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_qty"/>
<field name="product_uom" options="{'no_open': True, 'no_create': True}" string="Unit of Measure" groups="product.group_uom"/> <field name="product_uom" options="{'no_open': True, 'no_create': True}" string="Unit of Measure" groups="product.group_uom"/>
<field name="state"/> <field name="state"/>
@ -112,6 +116,7 @@
<field name="product_uom_qty"/> <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="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="location_id" invisible="1"/>
<field name="branch_id"/>
<field name="create_date" invisible="1" /> <field name="create_date" invisible="1" />
<field name="date_expected" invisible="1" /> <field name="date_expected" invisible="1" />
<field name="picking_type_id" invisible="1"/> <field name="picking_type_id" invisible="1"/>
@ -119,6 +124,7 @@
<field name="availability" invisible="1"/> <field name="availability" invisible="1"/>
<field name="reserved_availability" invisible="1"/> <field name="reserved_availability" invisible="1"/>
<field name="location_dest_id" invisible="1"/> <field name="location_dest_id" invisible="1"/>
<field name="branch_dest_id"/>
<field name="state"/> <field name="state"/>
</tree> </tree>
</field> </field>
@ -218,7 +224,9 @@
<group name="main_grp_col1"> <group name="main_grp_col1">
<field name="reference"/> <field name="reference"/>
<field name="location_id"/> <field name="location_id"/>
<field name="branch_id"/>
<field name="location_dest_id"/> <field name="location_dest_id"/>
<field name="branch_dest_id"/>
</group> </group>
<group name="main_grp_col2"> <group name="main_grp_col2">
<field name="product_id"/> <field name="product_id"/>

View File

@ -319,6 +319,7 @@
</group> </group>
<group> <group>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/> <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="group_id" groups="base.group_no_one"/>
<field name="priority" attrs="{'invisible': [('picking_type_code', '=', 'incoming')]}"/> <field name="priority" attrs="{'invisible': [('picking_type_code', '=', 'incoming')]}"/>
</group> </group>

View File

@ -48,6 +48,7 @@
<group> <group>
<field name="product_id"/> <field name="product_id"/>
<field name="location_id"/> <field name="location_id"/>
<field name="branch_id"/>
<field name="lot_id" groups="stock.group_production_lot"/> <field name="lot_id" groups="stock.group_production_lot"/>
<field name="package_id" groups="stock.group_tracking_lot"/> <field name="package_id" groups="stock.group_tracking_lot"/>
<field name="owner_id" groups="stock.group_tracking_owner"/> <field name="owner_id" groups="stock.group_tracking_owner"/>

View File

@ -52,6 +52,7 @@
</div> </div>
</group> </group>
<group> <group>
<field name="branch_id" />
<field name="lot_id" attrs="{'invisible': [('tracking', '=', 'none')], 'required': [('tracking', '!=', 'none')]}" groups="stock.group_production_lot"/> <field name="lot_id" attrs="{'invisible': [('tracking', '=', 'none')], 'required': [('tracking', '!=', 'none')]}" groups="stock.group_production_lot"/>
<field name="tracking" invisible="1"/> <field name="tracking" invisible="1"/>
<field name="package_id" groups="stock.group_tracking_lot"/> <field name="package_id" groups="stock.group_tracking_lot"/>

View File

@ -26,6 +26,7 @@
<group> <group>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/> <field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
<field name="partner_id"/> <field name="partner_id"/>
<field name="branch_id" options="{'no_create': True}"/>
</group> </group>
</group> </group>
<notebook colspan="4" groups="stock.group_adv_location"> <notebook colspan="4" groups="stock.group_adv_location">

View File

@ -376,6 +376,7 @@ class Users(models.Model):
for id in self.ids: for id in self.ids:
self.__uid_cache[db].pop(id, None) self.__uid_cache[db].pop(id, None)
self.clear_caches()
return res return res
@api.multi @api.multi