forked from OCA/product-variant
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] stock_picking_variant_mgmt (OCA#49)
================================================= Handle easily multiple variants on Stock Pickings ================================================= This module allows to add/modify of all the variants of a product in a direct screen without the need of handling them one by one. It also adds a convenient way of handling the transfer of the products in a 2D matrix with all the values of the first attribute in columns, and the rest of the combinations in rows. Configuration ============= * Configure your user to have any permission from "Inventory" group. * Create a product with 2 attributes and several values. Usage ===== * Go to Inventory > Dashboard. * Create a new picking from one of the existing picking types. * Press "Add variants" button located in the upper right corner of the "Initial Demand" tab. * A new screen will appear allowing you to select the products that have variants. * Once you select the product, a 2D matrix will appear with the first attribute values as columns and the second one (if any) as rows. * If there are already order lines for the product variants, the current quantity will be pre-filled in the matrix. * Change the quantities for the variant you want and click on "Transfer to picking" * Move lines for the variants will be created/removed to comply with the input you have done. As extra feature for saving steps, there's also a button on each existing line that corresponds to a variant that opens the dialog directly with the product selected. You are also able to manage variants on 1 dimension in the transfer: * Go to the "Operations" page. * Press on "Manage Variants Transfer" button in the upper right corner of the tab. * Change the quantities to transfer. * Click on "Transfer to picking" button. Known issues / Roadmap ====================== * The inline button for modifying quantities for an existing line won't work correctly until these 2 PRs are merged in Odoo: * odoo/odoo#13557 * odoo/odoo#13635 The patches are already integrated on OCB. * Make this work with product with more than 1 attribute.
- Loading branch information
1 parent
9db955f
commit 99d486e
Showing
14 changed files
with
667 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
|
||
================================================= | ||
Handle easily multiple variants on Stock Pickings | ||
================================================= | ||
|
||
This module allows to add/modify of all the variants of a product in a direct | ||
screen without the need of handling them one by one. | ||
|
||
It also adds a convenient way of handling the transfer of the products in a | ||
2D matrix with all the values of the first attribute in columns, and the | ||
rest of the combinations in rows. | ||
|
||
Configuration | ||
============= | ||
|
||
#. Configure your user to have any permission from "Inventory" group. | ||
#. Create a product with 2 attributes and several values. | ||
|
||
Usage | ||
===== | ||
|
||
#. Go to Inventory > Dashboard. | ||
#. Create a new picking from one of the existing picking types. | ||
#. Press "Add variants" button located in the upper right corner of the | ||
"Initial Demand" tab. | ||
#. A new screen will appear allowing you to select the products that have | ||
variants. | ||
#. Once you select the product, a 2D matrix will appear with the first | ||
attribute values as columns and the second one (if any) as rows. | ||
#. If there are already order lines for the product variants, the current | ||
quantity will be pre-filled in the matrix. | ||
#. Change the quantities for the variant you want and click on "Transfer to | ||
picking" | ||
#. Move lines for the variants will be created/removed to comply with the | ||
input you have done. | ||
|
||
As extra feature for saving steps, there's also a button on each existing line | ||
that corresponds to a variant that opens the dialog directly with the product | ||
selected. | ||
|
||
You are also able to manage variants on 1 dimension in the transfer: | ||
|
||
#. Go to the "Operations" page. | ||
#. Press on "Manage Variants Transfer" button in the upper right corner of the | ||
tab. | ||
#. Change the quantities to transfer. | ||
#. Click on "Transfer to picking" button. | ||
|
||
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas | ||
:alt: Try me on Runbot | ||
:target: https://runbot.odoo-community.org/runbot/137/9.0 | ||
|
||
Known issues / Roadmap | ||
====================== | ||
|
||
* The inline button for modifying quantities for an existing line won't | ||
work correctly until these 2 PRs are merged in Odoo: | ||
|
||
* https://github.com/odoo/odoo/pull/13557 | ||
* https://github.com/odoo/odoo/pull/13635 | ||
|
||
The patches are already integrated on OCB. | ||
|
||
* Make this work with product with more than 1 attribute. | ||
|
||
Credits | ||
======= | ||
|
||
Contributors | ||
------------ | ||
|
||
* Pedro M. Baeza <pedro.baeza@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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# -*- coding: utf-8 -*- | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from . import models | ||
from . import wizard |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 Pedro M. Baeza <pedro.baeza@tecnativa.com> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
{ | ||
'name': 'Handle easily multiple variants on Stock Pickings', | ||
'summary': 'Handle the addition/removal of multiple variants and the ' | ||
'quantities transferred in the Pickings.', | ||
'version': '9.0.1.0.0', | ||
'author': 'Tecnativa,' | ||
'Odoo Community Association (OCA)', | ||
'category': 'Inventory, Logistics, Warehousing', | ||
'license': 'AGPL-3', | ||
'website': 'https://www.tecnativa.com', | ||
'depends': [ | ||
'stock', | ||
'web_widget_x2many_2d_matrix', | ||
], | ||
'demo': [], | ||
'data': [ | ||
'wizard/stock_manage_variant_view.xml', | ||
'wizard/stock_transfer_manage_variant_view.xml', | ||
'views/stock_picking_view.xml', | ||
], | ||
'installable': True, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# -*- coding: utf-8 -*- | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from . import stock_move |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 Pedro M. Baeza <pedro.baeza@tecnativa.com> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from openerp import models, fields | ||
|
||
|
||
class StockMove(models.Model): | ||
_inherit = 'stock.move' | ||
|
||
product_attribute_value_ids = fields.Many2many( | ||
comodel_name='product.attribute.value', | ||
related="product_id.attribute_value_ids", | ||
readonly=True, | ||
) |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# -*- coding: utf-8 -*- | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from . import test_stock_picking_variant_mgmt |
161 changes: 161 additions & 0 deletions
161
stock_picking_variant_mgmt/tests/test_stock_picking_variant_mgmt.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 Pedro M. Baeza <pedro.baeza@tecnativa.com> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from openerp.tests import common | ||
|
||
|
||
@common.at_install(False) | ||
@common.post_install(True) | ||
class TestStockPickingVariantMgmt(common.SavepointCase): | ||
@classmethod | ||
def setUpClass(cls): | ||
super(TestStockPickingVariantMgmt, cls).setUpClass() | ||
cls.partner = cls.env['res.partner'].create({'name': 'Test partner'}) | ||
cls.attribute1 = cls.env['product.attribute'].create({ | ||
'name': 'Test Attribute 1', | ||
'value_ids': [ | ||
(0, 0, {'name': 'Value 1'}), | ||
(0, 0, {'name': 'Value 2'}), | ||
(0, 0, {'name': 'Value 3'}), | ||
(0, 0, {'name': 'Value 4'}), | ||
], | ||
}) | ||
cls.product_tmpl = cls.env['product.template'].create({ | ||
'name': 'Test template', | ||
'attribute_line_ids': [ | ||
(0, 0, { | ||
'attribute_id': cls.attribute1.id, | ||
'value_ids': [(6, 0, cls.attribute1.value_ids.ids)], | ||
}), | ||
], | ||
}) | ||
assert len(cls.product_tmpl.product_variant_ids) == 4 | ||
cls.warehouse = cls.env['stock.warehouse'].search([], limit=1) | ||
cls.picking_type = cls.env['stock.picking.type'].search([ | ||
('warehouse_id', '=', cls.warehouse.id), | ||
('code', '=', 'incoming'), | ||
], limit=1) | ||
cls.picking = cls.env['stock.picking'].create({ | ||
'partner_id': cls.partner.id, | ||
'picking_type_id': cls.picking_type.id, | ||
'location_id': cls.partner.property_stock_supplier.id, | ||
'location_dest_id': cls.picking_type.default_location_dest_id.id, | ||
}) | ||
cls.Move = cls.env['stock.move'] | ||
cls.product1 = cls.product_tmpl.product_variant_ids[0] | ||
move_vals = cls.Move.onchange_product_id( | ||
prod_id=cls.product1.id, | ||
loc_id=cls.picking.location_id.id, | ||
loc_dest_id=cls.picking.location_dest_id.id, | ||
partner_id=cls.picking.partner_id.id, | ||
).get('value', {}) | ||
move_vals.update({ | ||
'product_id': cls.product1.id, | ||
'picking_id': cls.picking.id, | ||
'product_uom_qty': 1, | ||
}) | ||
cls.move1 = cls.Move.create(move_vals) | ||
cls.product2 = cls.product_tmpl.product_variant_ids[1] | ||
move_vals = cls.Move.onchange_product_id( | ||
prod_id=cls.product2.id, | ||
loc_id=cls.picking.location_id.id, | ||
loc_dest_id=cls.picking.location_dest_id.id, | ||
partner_id=cls.picking.partner_id.id, | ||
).get('value', {}) | ||
move_vals.update({ | ||
'product_id': cls.product2.id, | ||
'picking_id': cls.picking.id, | ||
'product_uom_qty': 2, | ||
}) | ||
cls.move2 = cls.Move.create(move_vals) | ||
cls.Wizard = cls.env['stock.manage.variant'].with_context( | ||
active_ids=cls.picking.ids, active_id=cls.picking.id, | ||
active_model=cls.picking._name, | ||
) | ||
cls.product_single = cls.env['product.product'].create({ | ||
'name': 'Product without variants', | ||
}) | ||
move_vals = cls.Move.onchange_product_id( | ||
prod_id=cls.product_single.id, | ||
loc_id=cls.picking.location_id.id, | ||
loc_dest_id=cls.picking.location_dest_id.id, | ||
partner_id=cls.picking.partner_id.id, | ||
).get('value', {}) | ||
move_vals.update({ | ||
'product_id': cls.product_single.id, | ||
'picking_id': cls.picking.id, | ||
'product_uom_qty': 2, | ||
}) | ||
cls.move3 = cls.Move.create(move_vals) | ||
|
||
def test_add_variants(self): | ||
self.move1.unlink() | ||
self.move2.unlink() | ||
self.move3.unlink() | ||
wizard = self.Wizard.new({'product_tmpl_id': self.product_tmpl.id}) | ||
wizard._onchange_product_tmpl_id() | ||
wizard = wizard.create(wizard._convert_to_write(wizard._cache)) | ||
self.assertEqual(len(wizard.variant_line_ids), 4) | ||
wizard.variant_line_ids[0].product_uom_qty = 1 | ||
wizard.variant_line_ids[1].product_uom_qty = 2 | ||
wizard.variant_line_ids[2].product_uom_qty = 3 | ||
wizard.variant_line_ids[3].product_uom_qty = 4 | ||
wizard.button_transfer_to_picking() | ||
self.assertEqual(len(self.picking.move_lines), 4, | ||
"There should be 4 lines in the picking") | ||
self.assertEqual(self.picking.move_lines[0].product_uom_qty, 1) | ||
self.assertEqual(self.picking.move_lines[1].product_uom_qty, 2) | ||
self.assertEqual(self.picking.move_lines[2].product_uom_qty, 3) | ||
self.assertEqual(self.picking.move_lines[3].product_uom_qty, 4) | ||
|
||
def test_modify_variants(self): | ||
Wizard2 = self.Wizard.with_context( | ||
default_product_tmpl_id=self.product_tmpl.id, | ||
active_model='stock.move', | ||
active_id=self.move1.id, active_ids=self.move1.ids | ||
) | ||
wizard = Wizard2.create({}) | ||
wizard._onchange_product_tmpl_id() | ||
self.assertEqual( | ||
len(wizard.variant_line_ids.filtered('product_uom_qty')), 2, | ||
"There should be two fields with any quantity in the wizard." | ||
) | ||
wizard.variant_line_ids.filtered( | ||
lambda x: x.product_id == self.product1).product_uom_qty = 0 | ||
wizard.variant_line_ids.filtered( | ||
lambda x: x.product_id == self.product2).product_uom_qty = 10 | ||
wizard.button_transfer_to_picking() | ||
self.assertFalse(self.move1.exists(), "Move not removed.") | ||
self.assertEqual( | ||
self.move2.product_uom_qty, 10, "Move not changed quantity.", | ||
) | ||
|
||
def test_variant_transfer(self): | ||
self.picking.action_confirm() | ||
self.picking.action_assign() | ||
self.assertEqual(len(self.picking.pack_operation_ids), 3) | ||
wizard = self.env['stock.transfer.manage.variant'].with_context( | ||
active_model='stock.picking', active_ids=self.picking.ids, | ||
active_id=self.picking.id, | ||
).create({}) | ||
self.assertEqual(len(wizard.variant_line_ids), 6) | ||
wizard.variant_line_ids.filtered( | ||
lambda x: x.product_id == self.product1 | ||
).qty_done = 1 | ||
wizard.variant_line_ids.filtered( | ||
lambda x: x.product_id == self.product2 | ||
).qty_done = 2 | ||
wizard.variant_line_ids.filtered( | ||
lambda x: x.product_id == self.product_single | ||
).qty_done = 3 | ||
wizard.button_transfer_to_picking() | ||
self.assertEqual(self.picking.pack_operation_ids.filtered( | ||
lambda x: x.product_id == self.product1 | ||
).qty_done, 1) | ||
self.assertEqual(self.picking.pack_operation_ids.filtered( | ||
lambda x: x.product_id == self.product2 | ||
).qty_done, 2) | ||
self.assertEqual(self.picking.pack_operation_ids.filtered( | ||
lambda x: x.product_id == self.product_single | ||
).qty_done, 3) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<!-- Copyright 2017 Pedro M. Baeza <pedro.baeza@tecnativa.com> | ||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). --> | ||
<odoo> | ||
|
||
<record id="view_picking_form" model="ir.ui.view"> | ||
<field name="model">stock.picking</field> | ||
<field name="inherit_id" ref="stock.view_picking_form"/> | ||
<field name="arch" type="xml"> | ||
<xpath expr="//field[@name='pack_operation_product_ids']" position="before"> | ||
<div class="oe_button_box" name="button_box_transfer_variant_mgmt"> | ||
<button name="%(action_stock_transfer_manage_variant)d" | ||
type="action" | ||
string="Manage Variants Transfer" | ||
/> | ||
</div> | ||
</xpath> | ||
<xpath expr="//field[@name='move_lines']" position="before"> | ||
<div class="oe_button_box" name="button_box_variant_mgmt"> | ||
<button name="%(action_stock_manage_variant)d" | ||
type="action" | ||
string="Add or Modify Variants" | ||
states="draft,confirmed,assigned" | ||
/> | ||
</div> | ||
</xpath> | ||
</field> | ||
</record> | ||
|
||
<record id="view_move_picking_tree" model="ir.ui.view"> | ||
<field name="model">stock.move</field> | ||
<field name="inherit_id" ref="stock.view_move_picking_tree"/> | ||
<field name="arch" type="xml"> | ||
<field name="state" position="after"> | ||
<field name="product_tmpl_id" invisible="1"/> | ||
<field name="product_attribute_value_ids" invisible="1"/> | ||
<!-- Not working until https://github.com/odoo/odoo/pull/13558 --> | ||
<!-- Also https://github.com/odoo/odoo/pull/13635 is needed for correct template selection --> | ||
<button name="%(action_stock_manage_variant)d" | ||
type="action" | ||
string="Modify Variants" | ||
icon="fa-th" | ||
class="oe_edit_only" | ||
context="{'default_product_tmpl_id': product_tmpl_id}" | ||
attrs="{'invisible': ['|', ('state', 'not in', ('draft', 'confirmed', 'assigned')), ('product_attribute_value_ids', '=', [])]}" | ||
/> | ||
</field> | ||
</field> | ||
</record> | ||
|
||
</odoo> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# -*- coding: utf-8 -*- | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from . import stock_manage_variant | ||
from . import stock_transfer_manage_variant |
Oops, something went wrong.