mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[MIG] [9.0] stock_putaway_product: Migration to v9.0 (#197)
This commit is contained in:
committed by
Pedro M. Baeza
parent
27e273e7ca
commit
e7e5ccee63
90
stock_putaway_product/README.rst
Normal file
90
stock_putaway_product/README.rst
Normal file
@@ -0,0 +1,90 @@
|
||||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
|
||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
||||
:alt: License: AGPL-3
|
||||
|
||||
============================
|
||||
Putaway strategy per product
|
||||
============================
|
||||
|
||||
This module extends the functionality of the odoo putaway strategy.
|
||||
It defines a new type of putaway strategy where users can set a specific
|
||||
stock location per product.
|
||||
|
||||
On the product form, the case, rack, location fields are replaced with a
|
||||
specific putaway strategy and location id for the product.
|
||||
|
||||
A putaway strategy can be used to ensure that incoming products will be
|
||||
stored in the location set on the product form.
|
||||
|
||||
A recommended set-up is to create a separate putaway strategy for each
|
||||
warehouse. This will ensure that the same product will be placed in the
|
||||
appropriate location in each warehouse it is received.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
To install this module, just click the install button.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
To configure this module, you need to:
|
||||
|
||||
#. Go to Inventory > Configuration > Settings
|
||||
#. Enable "Manage several locations per warehouse" on Location & Warehouse >
|
||||
Multi Locations
|
||||
#. Enable "Advanced routing of products using rules" on Location & Warehouse >
|
||||
Routes
|
||||
#. Go to Inventory > Configuration > Warehouse Management > Locations
|
||||
#. On the main inventory location of your warehouse,
|
||||
set a new putaway strategy.
|
||||
#. For the new putaway strategy, select 'Fixed per product location'
|
||||
as method
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
To use this module, you need to:
|
||||
|
||||
#. Select the proper stock locations for each product on the product form
|
||||
on the "Inventory" tab
|
||||
|
||||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
|
||||
:alt: Try me on Runbot
|
||||
:target: https://runbot.odoo-community.org/runbot/153/8.0
|
||||
|
||||
Bug Tracker
|
||||
===========
|
||||
|
||||
Bugs are tracked on `GitHub Issues
|
||||
<https://github.com/OCA/stock-logistics-warehouse/issues>`_. In case of trouble
|
||||
, please check there if your issue has already been reported. If you spotted
|
||||
it first, help us smashing it by providing a detailed and welcomed feedback.
|
||||
|
||||
Images
|
||||
------
|
||||
|
||||
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* Jos De Graeve - Apertoso N.V. <Jos.DeGraeve@apertoso.be>
|
||||
* Carlos Dauden - Tecnativa <carlos.dauden@tecnativa.com>
|
||||
|
||||
|
||||
Maintainer
|
||||
----------
|
||||
|
||||
.. image:: https://odoo-community.org/logo.png
|
||||
:alt: Odoo Community Association
|
||||
:target: https://odoo-community.org
|
||||
|
||||
This module is maintained by the OCA.
|
||||
|
||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
||||
mission is to support the collaborative development of Odoo features and
|
||||
promote its widespread use.
|
||||
|
||||
To contribute to this module, please visit https://odoo-community.org.
|
||||
|
||||
6
stock_putaway_product/__init__.py
Normal file
6
stock_putaway_product/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Jos De Graeve - Apertoso N.V. <Jos.DeGraeve@apertoso.be>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import models
|
||||
from . import tests
|
||||
from . import wizard
|
||||
27
stock_putaway_product/__openerp__.py
Normal file
27
stock_putaway_product/__openerp__.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Jos De Graeve - Apertoso N.V. <Jos.DeGraeve@apertoso.be>
|
||||
# © 2016 Carlos Dauden - Tecnativa <carlos.dauden@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
{
|
||||
'name': 'Putaway strategy per product',
|
||||
'summary': 'Set a product location and put-away strategy per product',
|
||||
'version': '9.0.1.0.0',
|
||||
'category': 'Inventory',
|
||||
'website': 'http://www.apertoso.be',
|
||||
'author': 'Apertoso N.V., '
|
||||
'Tecnativa, '
|
||||
'Odoo Community Association (OCA)',
|
||||
'license': 'AGPL-3',
|
||||
'depends': [
|
||||
'product',
|
||||
'stock'
|
||||
],
|
||||
'data': [
|
||||
'views/product.xml',
|
||||
'views/product_putaway.xml',
|
||||
'security/ir.model.access.csv',
|
||||
],
|
||||
'demo': [
|
||||
'demo/product_putaway.xml',
|
||||
]
|
||||
}
|
||||
26
stock_putaway_product/demo/product_putaway.xml
Normal file
26
stock_putaway_product/demo/product_putaway.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="product_putaway_per_product_wh"
|
||||
model="product.putaway">
|
||||
<field name="name">WH - Putaway Per Product</field>
|
||||
<field name="method">per_product</field>
|
||||
</record>
|
||||
|
||||
<record id="stock.stock_location_stock"
|
||||
model="stock.location">
|
||||
<field name="putaway_strategy_id"
|
||||
ref="product_putaway_per_product_wh"/>
|
||||
</record>
|
||||
|
||||
<record id="product_putaway_strategy_product_4"
|
||||
model="stock.product.putaway.strategy">
|
||||
<field name="product_product_id"
|
||||
ref="product.product_product_4"/>
|
||||
<field name="product_tmpl_id"
|
||||
ref="product.product_product_4_product_template"/>
|
||||
<field name="putaway_id"
|
||||
ref="product_putaway_per_product_wh"/>
|
||||
<field name="fixed_location_id"
|
||||
ref="stock.stock_location_components"/>
|
||||
</record>
|
||||
</odoo>
|
||||
4
stock_putaway_product/models/__init__.py
Normal file
4
stock_putaway_product/models/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from . import product_putaway
|
||||
from . import product
|
||||
24
stock_putaway_product/models/product.py
Normal file
24
stock_putaway_product/models/product.py
Normal file
@@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Jos De Graeve - Apertoso N.V. <Jos.DeGraeve@apertoso.be>
|
||||
# © 2016 Carlos Dauden - Tecnativa <carlos.dauden@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from openerp import fields, models
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
||||
product_putaway_ids = fields.One2many(
|
||||
comodel_name='stock.product.putaway.strategy',
|
||||
inverse_name='product_tmpl_id',
|
||||
string="Product stock locations")
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
_inherit = 'product.product'
|
||||
|
||||
product_putaway_ids = fields.One2many(
|
||||
comodel_name='stock.product.putaway.strategy',
|
||||
inverse_name='product_product_id',
|
||||
string="Product stock locations")
|
||||
79
stock_putaway_product/models/product_putaway.py
Normal file
79
stock_putaway_product/models/product_putaway.py
Normal file
@@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Jos De Graeve - Apertoso N.V. <Jos.DeGraeve@apertoso.be>
|
||||
# © 2016 Carlos Dauden - Tecnativa <carlos.dauden@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from openerp import models, fields, api, _
|
||||
|
||||
|
||||
class ProductPutawayStrategy(models.Model):
|
||||
_inherit = 'product.putaway'
|
||||
|
||||
@api.model
|
||||
def _get_putaway_options(self):
|
||||
ret = super(ProductPutawayStrategy, self)._get_putaway_options()
|
||||
return ret + [('per_product', 'Fixed per product location')]
|
||||
|
||||
product_location_ids = fields.One2many(
|
||||
comodel_name='stock.product.putaway.strategy',
|
||||
inverse_name='putaway_id',
|
||||
string='Fixed per product location',
|
||||
copy=True)
|
||||
method = fields.Selection(selection=_get_putaway_options)
|
||||
|
||||
@api.multi
|
||||
def get_product_putaway_strategies(self, product):
|
||||
self.ensure_one()
|
||||
return self.product_location_ids.filtered(lambda x: (
|
||||
x.product_product_id == product or
|
||||
(not x.product_product_id and
|
||||
x.product_tmpl_id == product.product_tmpl_id)))
|
||||
|
||||
@api.model
|
||||
def putaway_apply(self, putaway_strategy, product):
|
||||
if putaway_strategy.method == 'per_product':
|
||||
strategies = putaway_strategy.get_product_putaway_strategies(
|
||||
product)
|
||||
return strategies[:1].fixed_location_id.id
|
||||
else:
|
||||
return super(ProductPutawayStrategy, self).putaway_apply(
|
||||
putaway_strategy, product)
|
||||
|
||||
|
||||
class StockFixedPutawayStrategy(models.Model):
|
||||
_name = 'stock.product.putaway.strategy'
|
||||
_rec_name = 'product_product_id'
|
||||
_order = 'putaway_id, sequence'
|
||||
|
||||
_sql_constraints = [(
|
||||
'putaway_product_location_unique',
|
||||
'unique(putaway_id,product_product_id,fixed_location_id)',
|
||||
_('There is a duplicate location by put away assignment!')
|
||||
)]
|
||||
|
||||
@api.model
|
||||
def get_default_inventory_id(self):
|
||||
return self.env['stock.inventory'].search(
|
||||
[('id', '=', self.env.context.get('active_id', False))])
|
||||
|
||||
putaway_id = fields.Many2one(
|
||||
comodel_name='product.putaway',
|
||||
string='Put Away Strategy',
|
||||
required=True,
|
||||
index=True)
|
||||
product_tmpl_id = fields.Many2one(
|
||||
comodel_name='product.template',
|
||||
string='Product Template',
|
||||
index=True,
|
||||
oldname='product_template_id',
|
||||
required=True)
|
||||
product_product_id = fields.Many2one(
|
||||
comodel_name='product.product',
|
||||
string='Product Variant',
|
||||
index=True)
|
||||
fixed_location_id = fields.Many2one(
|
||||
comodel_name='stock.location',
|
||||
string='Location',
|
||||
required=True,
|
||||
domain=[('usage', '=', 'internal')])
|
||||
sequence = fields.Integer()
|
||||
3
stock_putaway_product/security/ir.model.access.csv
Normal file
3
stock_putaway_product/security/ir.model.access.csv
Normal file
@@ -0,0 +1,3 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_stock_product_putaway_strategy,stock_product_putaway_strategy managers,model_stock_product_putaway_strategy,stock.group_stock_manager,1,1,1,1
|
||||
access_stock_product_putaway_user,stock_product_putaway_strategy user,model_stock_product_putaway_strategy,stock.group_stock_user,1,0,0,0
|
||||
|
5
stock_putaway_product/tests/__init__.py
Normal file
5
stock_putaway_product/tests/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Jos De Graeve - Apertoso N.V. <Jos.DeGraeve@apertoso.be>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import test_product_putaway
|
||||
44
stock_putaway_product/tests/test_product_putaway.py
Normal file
44
stock_putaway_product/tests/test_product_putaway.py
Normal file
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Jos De Graeve - Apertoso N.V. <Jos.DeGraeve@apertoso.be>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from openerp.tests import common
|
||||
|
||||
|
||||
class TestProductPutaway(common.TransactionCase):
|
||||
# Check if "per_product" is a valid putaway method
|
||||
def test_01_putaway_methods(self):
|
||||
field_method = self.env[
|
||||
'product.putaway']._fields.get('method')
|
||||
self.assertIn('per_product', field_method.get_values(self.env))
|
||||
|
||||
def test_02_putway_apply(self):
|
||||
putaway_per_product = self.browse_ref(
|
||||
'stock_putaway_product.product_putaway_per_product_wh')
|
||||
product_ipad = self.browse_ref(
|
||||
'product.product_product_4')
|
||||
location_shelf1 = self.browse_ref(
|
||||
'stock.stock_location_components')
|
||||
|
||||
self.assertEqual(
|
||||
self.env['product.putaway'].putaway_apply(
|
||||
putaway_per_product, product_ipad),
|
||||
location_shelf1.id)
|
||||
|
||||
def test_03_stock_change_product_qty_default(self):
|
||||
product_ipad = self.browse_ref(
|
||||
'product.product_product_4')
|
||||
location_shelf1 = self.browse_ref(
|
||||
'stock.stock_location_components')
|
||||
|
||||
wiz_obj = self.env['stock.change.product.qty']
|
||||
|
||||
test_context = {
|
||||
'active_model': 'product.product',
|
||||
'active_id': product_ipad.id,
|
||||
}
|
||||
wiz_instance = wiz_obj.with_context(test_context).create(
|
||||
{'product_tmpl_id': product_ipad.product_tmpl_id.id})
|
||||
self.assertEqual(
|
||||
wiz_instance.location_id,
|
||||
location_shelf1)
|
||||
31
stock_putaway_product/views/product.xml
Normal file
31
stock_putaway_product/views/product.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- © 2016 Jos De Graeve - Apertoso N.V. <Jos.DeGraeve@apertoso.be>
|
||||
© 2016 Carlos Dauden <carlos.dauden@tecnativa.com>
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl-3). -->
|
||||
<odoo>
|
||||
<record id="view_template_property_form" model="ir.ui.view">
|
||||
<field name="name">product.template.product.form</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="stock.view_template_property_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group[@name='stock_property']" position="before">
|
||||
<group colspan="4" name="putaway" string="Put Away Locations">
|
||||
<field name="product_putaway_ids"
|
||||
context="{'default_product_tmpl_id': is_product_variant and product_tmpl_id or active_id,
|
||||
'default_product_product_id': is_product_variant and active_id or False}"
|
||||
nolabel="1" colspan="2">
|
||||
<tree editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="putaway_id"/>
|
||||
<field name="product_tmpl_id" invisible="1"/>
|
||||
<field name="product_product_id"
|
||||
invisible="context.get('default_product_product_id', True)"
|
||||
domain="[('product_tmpl_id', '=', product_tmpl_id)]"/>
|
||||
<field name="fixed_location_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
47
stock_putaway_product/views/product_putaway.xml
Normal file
47
stock_putaway_product/views/product_putaway.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
<record id="view_putaway" model="ir.ui.view">
|
||||
<field name="name">product.putaway.form.byproduct</field>
|
||||
<field name="model">product.putaway</field>
|
||||
<field name="inherit_id" ref="stock.view_putaway"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='method']/.." position="after">
|
||||
<div attrs="{'invisible': [('method', '!=', 'per_product')]}">
|
||||
<separator string="Fixed Locations Per Product"/>
|
||||
<field name="product_location_ids" colspan="4" nolabel="1">
|
||||
<tree editable="top">
|
||||
<field name="sequence" widget='handle'/>
|
||||
<field name="product_tmpl_id"/>
|
||||
<field name="product_product_id"/>
|
||||
<field name="fixed_location_id"/>
|
||||
</tree>
|
||||
</field>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_putaway_strategy_view_form" model="ir.ui.view">
|
||||
<field name="name">product_putaway_strategy_view_form</field>
|
||||
<field name="model">stock.product.putaway.strategy</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Product putaway stragegy">
|
||||
<group>
|
||||
<group colspan="4">
|
||||
<field name="putaway_id"/>
|
||||
</group>
|
||||
<group colspan="4">
|
||||
<field name="product_tmpl_id" invisible="1"/>
|
||||
<field name="product_product_id"
|
||||
domain="[('product_tmpl_id','=',product_tmpl_id)]"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="fixed_location_id"
|
||||
domain="[('usage','=','internal')]"/>
|
||||
</group>
|
||||
</group>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
5
stock_putaway_product/wizard/__init__.py
Normal file
5
stock_putaway_product/wizard/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Jos De Graeve - Apertoso N.V. <Jos.DeGraeve@apertoso.be>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import stock_change_product_qty
|
||||
29
stock_putaway_product/wizard/stock_change_product_qty.py
Normal file
29
stock_putaway_product/wizard/stock_change_product_qty.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# © 2016 Jos De Graeve - Apertoso N.V. <Jos.DeGraeve@apertoso.be>
|
||||
# © 2016 Carlos Dauden - Tecnativa <carlos.dauden@tecnativa.com>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from openerp import models, api
|
||||
|
||||
|
||||
class StockChangeProductQty(models.TransientModel):
|
||||
_inherit = "stock.change.product.qty"
|
||||
|
||||
# When a user updates stock qty on the product form, propose the
|
||||
# right location to update stock.
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
res = super(StockChangeProductQty, self).default_get(fields)
|
||||
|
||||
product_product_id = res.get('product_id')
|
||||
location_id = res.get('location_id')
|
||||
|
||||
if product_product_id and location_id:
|
||||
putaway = self.env['stock.product.putaway.strategy'].search([
|
||||
('product_product_id', '=', product_product_id),
|
||||
('fixed_location_id', 'child_of', location_id),
|
||||
], limit=1)
|
||||
if putaway:
|
||||
res.update({'location_id': putaway.fixed_location_id.id})
|
||||
|
||||
return res
|
||||
Reference in New Issue
Block a user