[MIG] [9.0] stock_putaway_product: Migration to v9.0 (#197)

This commit is contained in:
Carlos Dauden
2016-11-07 11:21:44 +01:00
committed by Pedro M. Baeza
parent 27e273e7ca
commit e7e5ccee63
14 changed files with 420 additions and 0 deletions

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

View 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

View 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',
]
}

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

View File

@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
from . import product_putaway
from . import product

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

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

View 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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_stock_product_putaway_strategy stock_product_putaway_strategy managers model_stock_product_putaway_strategy stock.group_stock_manager 1 1 1 1
3 access_stock_product_putaway_user stock_product_putaway_strategy user model_stock_product_putaway_strategy stock.group_stock_user 1 0 0 0

View 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

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

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

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

View 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

View 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