From 3b93ab98be13f895156ea453d8098d4e4879c25a Mon Sep 17 00:00:00 2001 From: mpanarin Date: Wed, 9 Jan 2019 01:14:46 +0200 Subject: [PATCH] [IMP] refactor to use pickings instead of inventories --- stock_move_location/__init__.py | 1 - stock_move_location/__manifest__.py | 2 - .../data/stock_move_sequence.xml | 15 --- .../i18n/stock_move_location.pot | 107 ++++++++++++----- stock_move_location/models/__init__.py | 6 - stock_move_location/models/inventory_line.py | 47 -------- stock_move_location/models/stock_inventory.py | 54 --------- stock_move_location/readme/USAGE.rst | 5 +- stock_move_location/tests/test_common.py | 27 ++++- .../tests/test_move_location.py | 111 ++++++------------ stock_move_location/views/stock_view.xml | 20 ---- .../wizard/stock_move_location.py | 107 ++++------------- .../wizard/stock_move_location.xml | 3 +- .../wizard/stock_move_location_line.py | 53 +++++++++ 14 files changed, 223 insertions(+), 335 deletions(-) delete mode 100644 stock_move_location/data/stock_move_sequence.xml delete mode 100644 stock_move_location/models/__init__.py delete mode 100644 stock_move_location/models/inventory_line.py delete mode 100644 stock_move_location/models/stock_inventory.py delete mode 100755 stock_move_location/views/stock_view.xml diff --git a/stock_move_location/__init__.py b/stock_move_location/__init__.py index 5918b27a3..93569fb46 100644 --- a/stock_move_location/__init__.py +++ b/stock_move_location/__init__.py @@ -2,5 +2,4 @@ # Copyright 2018 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) -from . import models from . import wizard diff --git a/stock_move_location/__manifest__.py b/stock_move_location/__manifest__.py index 4cf6ae6ec..d9b725fc5 100644 --- a/stock_move_location/__manifest__.py +++ b/stock_move_location/__manifest__.py @@ -16,8 +16,6 @@ ], "category": "Stock", "data": [ - 'data/stock_move_sequence.xml', - 'views/stock_view.xml', 'wizard/stock_move_location.xml', ], } diff --git a/stock_move_location/data/stock_move_sequence.xml b/stock_move_location/data/stock_move_sequence.xml deleted file mode 100644 index e27670c5d..000000000 --- a/stock_move_location/data/stock_move_sequence.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - Inventory Move - stock.inventory.move - MOV - 3 - 1 - 1 - - - - diff --git a/stock_move_location/i18n/stock_move_location.pot b/stock_move_location/i18n/stock_move_location.pot index 80d94cf11..ebbc50d73 100644 --- a/stock_move_location/i18n/stock_move_location.pot +++ b/stock_move_location/i18n/stock_move_location.pot @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 11.0+e\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-12-28 14:49+0000\n" -"PO-Revision-Date: 2018-12-28 14:49+0000\n" +"POT-Creation-Date: 2019-01-08 23:43+0000\n" +"PO-Revision-Date: 2019-01-08 23:43+0000\n" "Last-Translator: <>\n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -16,39 +16,47 @@ msgstr "" "Plural-Forms: \n" #. module: stock_move_location -#: model:ir.ui.view,arch_db:stock_move_location.view_stock_move_location_form_stock_move_location +#: model:ir.ui.view,arch_db:stock_move_location.view_wiz_stock_move_location_form_stock_move_location +msgid "Add all" +msgstr "" + +#. module: stock_move_location +#: model:ir.ui.view,arch_db:stock_move_location.view_wiz_stock_move_location_form_stock_move_location msgid "Cancel" msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_inventory_comments -msgid "Comments" +#: model:ir.ui.view,arch_db:stock_move_location.view_wiz_stock_move_location_form_stock_move_location +msgid "Clear all" msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_create_uid +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_create_uid +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_create_uid msgid "Created by" msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_create_date +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_create_date +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_create_date msgid "Created on" msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_inventory_destination_location_id -#: model:ir.model.fields,field_description:stock_move_location.field_stock_inventory_line_destination_location_id -#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_destination_location_id +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_destination_location_id +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_destination_location_id msgid "Destination Location" msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_display_name +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_display_name +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_display_name msgid "Display Name" msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_id_9042 +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_id +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_id msgid "ID" msgstr "" @@ -57,61 +65,104 @@ msgstr "" msgid "Inventory" msgstr "" +#. module: stock_move_location +#: model:ir.ui.view,arch_db:stock_move_location.view_wiz_stock_move_location_form_stock_move_location +msgid "Inventory Details" +msgstr "" + #. module: stock_move_location #: model:ir.model,name:stock_move_location.model_stock_inventory_line msgid "Inventory Line" msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location___last_update +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location___last_update +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line___last_update msgid "Last Modified on" msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_write_uid +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_write_uid +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_write_uid msgid "Last Updated by" msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_write_date +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_write_date +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_write_date msgid "Last Updated on" msgstr "" #. module: stock_move_location -#: model:ir.ui.view,arch_db:stock_move_location.view_stock_move_location_form_stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_lot_id +msgid "Lot/Serial Number" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_max_quantity +msgid "Maximum available quantity" +msgstr "" + +#. module: stock_move_location +#: model:ir.ui.view,arch_db:stock_move_location.view_wiz_stock_move_location_form_stock_move_location msgid "Move Location" msgstr "" #. module: stock_move_location -#: model:ir.actions.act_window,name:stock_move_location.stock_move_location_action +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_stock_move_location_line_ids +msgid "Move Location lines" +msgstr "" + +#. module: stock_move_location +#: model:ir.actions.act_window,name:stock_move_location.wiz_stock_move_location_action #: model:ir.ui.menu,name:stock_move_location.menuitem_move_location msgid "Move from location..." msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_move_location_origin_location_id +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_move_location_wizard_id +msgid "Move location Wizard" +msgstr "" + +#. module: stock_move_location +#: code:addons/stock_move_location/wizard/stock_move_location_line.py:56 +#, python-format +msgid "Move quantity can not exceed max quantity or be negative" +msgstr "" + +#. module: stock_move_location +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_origin_location_id +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_origin_location_id msgid "Origin Location" msgstr "" #. module: stock_move_location -#: code:addons/stock_move_location/models/stock_inventory.py:40 -#, python-format -msgid "Please select the destination of your move" +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_product_id +msgid "Product" msgstr "" #. module: stock_move_location -#: model:ir.model,name:stock_move_location.model_stock_move -msgid "Stock Move" +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_product_uom_id +msgid "Product Unit of Measure" msgstr "" #. module: stock_move_location -#: model:ir.model.fields,field_description:stock_move_location.field_stock_inventory_inventory_type -#: model:ir.model.fields,field_description:stock_move_location.field_stock_inventory_line_inventory_type -msgid "Type" +#: model:ir.model.fields,field_description:stock_move_location.field_wiz_stock_move_location_line_move_quantity +msgid "Quantity to move" msgstr "" #. module: stock_move_location -#: model:ir.model,name:stock_move_location.model_stock_move_location -msgid "stock.move.location" +#: model:ir.ui.view,arch_db:stock_move_location.view_wiz_stock_move_location_form_stock_move_location +msgid "UoM" +msgstr "" + +#. module: stock_move_location +#: model:ir.model,name:stock_move_location.model_wiz_stock_move_location +msgid "wiz.stock.move.location" +msgstr "" + +#. module: stock_move_location +#: model:ir.model,name:stock_move_location.model_wiz_stock_move_location_line +msgid "wiz.stock.move.location.line" msgstr "" diff --git a/stock_move_location/models/__init__.py b/stock_move_location/models/__init__.py deleted file mode 100644 index 067b2103c..000000000 --- a/stock_move_location/models/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# Copyright (C) 2011 Julius Network Solutions SARL -# Copyright 2018 Camptocamp SA -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - -from . import stock_inventory -from . import inventory_line diff --git a/stock_move_location/models/inventory_line.py b/stock_move_location/models/inventory_line.py deleted file mode 100644 index cb41cad19..000000000 --- a/stock_move_location/models/inventory_line.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2018 Camptocamp SA -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - -from odoo import fields, models - - -class InventoryLine(models.Model): - _inherit = "stock.inventory.line" - - destination_location_id = fields.Many2one( - related="inventory_id.destination_location_id", - readonly=True, - ) - inventory_type = fields.Selection( - related="inventory_id.inventory_type", - ) - - def _get_move_location_values(self): - self.ensure_one() - location_id = self.inventory_id.destination_location_id - date = self.inventory_id.date - return { - 'name': ("MOVE:{}:{}".format( - self.inventory_id.id, - self.inventory_id.name, - )), - 'move_line_ids': self._get_move_line_location_values(), - 'product_id': self.product_id.id, - 'product_uom': self.product_uom_id.id, - 'location_id': self.location_id.id, - 'location_dest_id': location_id.id, - 'date': date, - } - - def _get_move_line_location_values(self): - self.ensure_one() - location_id = self.inventory_id.destination_location_id - return [ - (0, 0, { - 'product_id': self.product_id.id, - 'lot_id': self.prod_lot_id.id, - 'location_id': self.location_id.id, - 'location_dest_id': location_id.id, - 'qty_done': self.product_qty, - 'product_uom_id': self.product_uom_id.id, - }) - ] diff --git a/stock_move_location/models/stock_inventory.py b/stock_move_location/models/stock_inventory.py deleted file mode 100644 index b2744f3e1..000000000 --- a/stock_move_location/models/stock_inventory.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) 2011 Julius Network Solutions SARL -# Copyright 2018 Camptocamp SA -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) - -import logging - -from odoo import _, fields, models -from odoo.exceptions import ValidationError - - -_logger = logging.getLogger(__name__) - - -class StockInventory(models.Model): - _inherit = "stock.inventory" - - def _select_inventory_type(self): - return [ - ('normal', 'Inventory'), - ('move', 'Location Move'), - ] - - inventory_type = fields.Selection( - string='Type', - selection="_select_inventory_type", - default='normal', - ) - destination_location_id = fields.Many2one( - string='Destination Location', - comodel_name='stock.location', - ) - comments = fields.Text( - string='Comments', - ) - - def move_stock(self): - for inventory in self: - if not inventory.destination_location_id: - raise ValidationError( - _('Please select the destination of your move') - ) - moves = [ - (0, 0, line._get_move_location_values()) - for line in inventory.line_ids - ] - self.write({ - 'move_ids': moves, - }) - self.mapped('move_ids')._action_done() - self.write({ - "state": "done", - }) - _logger.info("Move '{}' is done.".format(inventory.name)) - return True diff --git a/stock_move_location/readme/USAGE.rst b/stock_move_location/readme/USAGE.rst index c047b1e2b..60efc93b1 100644 --- a/stock_move_location/readme/USAGE.rst +++ b/stock_move_location/readme/USAGE.rst @@ -1,9 +1,10 @@ * A new menuitem Stock > Move from location... opens a wizard where 2 location ca be specified. -* Select origin and destination locations and press "MOVE LOCATION" +* Select origin and destination locations and press "IMMEDIATE TRANSFER" or "PLANNED TRANSFER" * Press `ADD ALL` button to add all products available * Those lines can be edited. Move quantity can't be more than a max available quantity * Move doesn't care about the reservations and will move stuff anyway * If during you operation with the wizard the real quantity will change it will move only the available quantity at the button press -* Products will be moved and a form view of inventory that did that will show up +* Products will be moved and a form view of picking that did that will show up +* If "PLANNED TRANSFER" is used - the picking won't be validated automatically diff --git a/stock_move_location/tests/test_common.py b/stock_move_location/tests/test_common.py index a002da970..bb158ce15 100644 --- a/stock_move_location/tests/test_common.py +++ b/stock_move_location/tests/test_common.py @@ -9,7 +9,7 @@ class TestsCommon(common.SavepointCase): @classmethod def setUpClass(cls): - super(TestsCommon, cls).setUpClass() + super().setUpClass() cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) cls.location_obj = cls.env["stock.location"] product_obj = cls.env["product.product"] @@ -49,6 +49,31 @@ class TestsCommon(common.SavepointCase): 'product_id': cls.product_lots.id, }) + def setup_product_amounts(self): + self.set_product_amount( + self.product_no_lots, + self.internal_loc_1, + 123, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot1, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot2, + ) + self.set_product_amount( + self.product_lots, + self.internal_loc_1, + 1, + lot_id=self.lot3, + ) + def set_product_amount(self, product, location, amount, lot_id=None): self.env['stock.quant']._update_available_quantity( product, diff --git a/stock_move_location/tests/test_move_location.py b/stock_move_location/tests/test_move_location.py index e9a2b4cd1..2dec616e1 100644 --- a/stock_move_location/tests/test_move_location.py +++ b/stock_move_location/tests/test_move_location.py @@ -8,33 +8,16 @@ from odoo.exceptions import ValidationError class TestMoveLocation(TestsCommon): + def _create_wizard(self, origin_location, destination_location): + return self.wizard_obj.create({ + "origin_location_id": origin_location.id, + "destination_location_id": destination_location.id, + }) + def test_move_location_wizard(self): """Test a simple move. """ - self.set_product_amount( - self.product_no_lots, - self.internal_loc_1, - 123, - ) - self.set_product_amount( - self.product_lots, - self.internal_loc_1, - 1, - lot_id=self.lot1, - ) - self.set_product_amount( - self.product_lots, - self.internal_loc_1, - 1, - lot_id=self.lot2, - ) - self.set_product_amount( - self.product_lots, - self.internal_loc_1, - 1, - lot_id=self.lot3, - ) - + self.setup_product_amounts() wizard = self._create_wizard(self.internal_loc_1, self.internal_loc_2) wizard.add_lines() wizard.action_move_location() @@ -63,39 +46,10 @@ class TestMoveLocation(TestsCommon): self.product_lots, self.internal_loc_2, 1, self.lot1, ) - def _create_wizard(self, origin_location, destination_location): - return self.wizard_obj.create({ - "origin_location_id": origin_location.id, - "destination_location_id": destination_location.id, - }) - def test_move_location_wizard_amount(self): """Can't move more than exists """ - self.set_product_amount( - self.product_no_lots, - self.internal_loc_1, - 123, - ) - self.set_product_amount( - self.product_lots, - self.internal_loc_1, - 1, - lot_id=self.lot1, - ) - self.set_product_amount( - self.product_lots, - self.internal_loc_1, - 1, - lot_id=self.lot2, - ) - self.set_product_amount( - self.product_lots, - self.internal_loc_1, - 1, - lot_id=self.lot3, - ) - + self.setup_product_amounts() wizard = self._create_wizard(self.internal_loc_1, self.internal_loc_2) wizard.add_lines() with self.assertRaises(ValidationError): @@ -104,29 +58,7 @@ class TestMoveLocation(TestsCommon): def test_move_location_wizard_ignore_reserved(self): """Can't move more than exists """ - self.set_product_amount( - self.product_no_lots, - self.internal_loc_1, - 123, - ) - self.set_product_amount( - self.product_lots, - self.internal_loc_1, - 1, - lot_id=self.lot1, - ) - self.set_product_amount( - self.product_lots, - self.internal_loc_1, - 1, - lot_id=self.lot2, - ) - self.set_product_amount( - self.product_lots, - self.internal_loc_1, - 1, - lot_id=self.lot3, - ) + self.setup_product_amounts() wizard = self._create_wizard(self.internal_loc_1, self.internal_loc_2) wizard.add_lines() # reserve some quants @@ -152,3 +84,28 @@ class TestMoveLocation(TestsCommon): self.check_product_amount( self.product_lots, self.internal_loc_2, 1, self.lot1, ) + + def test_wizard_clear_lines(self): + """Test lines getting cleared properly + """ + self.setup_product_amounts() + wizard = self._create_wizard(self.internal_loc_1, self.internal_loc_2) + wizard.add_lines() + self.assertEqual(len(wizard.stock_move_location_line_ids), 4) + wizard._onchange_locations() + self.assertEqual(len(wizard.stock_move_location_line_ids), 0) + + def test_planned_transfer(self): + """Test planned transfer + """ + self.setup_product_amounts() + wizard = self._create_wizard(self.internal_loc_1, self.internal_loc_2) + wizard.add_lines() + wizard.with_context({'planned': True}).action_move_location() + picking = wizard.picking_id + self.assertEqual(picking.state, 'draft') + self.assertEqual(len(picking.move_line_ids), 4) + self.assertEqual( + sorted(picking.move_line_ids.mapped("qty_done")), + [1, 1, 1, 123], + ) diff --git a/stock_move_location/views/stock_view.xml b/stock_move_location/views/stock_view.xml deleted file mode 100755 index 4bffb96b7..000000000 --- a/stock_move_location/views/stock_view.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - stock.inventory.form.stock_move_location - stock.inventory - - - - - - - - - - - - - - diff --git a/stock_move_location/wizard/stock_move_location.py b/stock_move_location/wizard/stock_move_location.py index 343a870ec..eae00cb72 100644 --- a/stock_move_location/wizard/stock_move_location.py +++ b/stock_move_location/wizard/stock_move_location.py @@ -25,6 +25,10 @@ class StockMoveLocationWizard(models.TransientModel): comodel_name="wiz.stock.move.location.line", inverse_name="move_location_wizard_id", ) + picking_id = fields.Many2one( + string="Connected Picking", + comodel_name="stock.picking", + ) @api.onchange('origin_location_id', 'destination_location_id') def _onchange_locations(self): @@ -43,42 +47,33 @@ class StockMoveLocationWizard(models.TransientModel): def _get_locations_domain(self): return [('usage', '=', 'internal')] + def _create_picking(self): + return self.env['stock.picking'].create({ + 'picking_type_id': self.env.ref('stock.picking_type_internal').id, + 'location_id': self.origin_location_id.id, + 'location_dest_id': self.destination_location_id.id, + }) + + def _create_moves(self, picking): + return self.stock_move_location_line_ids.create_move_lines(picking) + + @api.multi def action_move_location(self): - inventory_obj = self.env["stock.inventory"] - collected_inventory = inventory_obj.create( - self._get_collected_inventory_values() - ) - collected_inventory.action_start() - self.set_inventory_lines(collected_inventory) - collected_inventory.move_stock() - return self._get_inventory_action(collected_inventory.id) + self.ensure_one() + picking = self._create_picking() + self._create_moves(picking) + if not self.env.context.get("planned"): + picking.button_validate() + self.picking_id = picking + return self._get_picking_action(picking.id) - def _get_collected_inventory_name(self): - sequence = self.env['ir.sequence'].next_by_code( - 'stock.inventory.move') or '/' - res = "{sequence}:{location_from}:{location_to}".format( - sequence=sequence, - location_from=self.origin_location_id.display_name, - location_to=self.destination_location_id.display_name, - ) - return res - - def _get_collected_inventory_values(self): - return { - "name": self._get_collected_inventory_name(), - "location_id": self.origin_location_id.id, - "inventory_type": "move", - "destination_location_id": self.destination_location_id.id, - "filter": "partial", - } - - def _get_inventory_action(self, inventory_id): - action = self.env.ref("stock.action_inventory_form").read()[0] - form_view = self.env.ref("stock.view_inventory_form").id + def _get_picking_action(self, pickinig_id): + action = self.env.ref("stock.action_picking_tree_all").read()[0] + form_view = self.env.ref("stock.view_picking_form").id action.update({ "view_mode": "form", "views": [(form_view, "form")], - "res_id": inventory_id, + "res_id": pickinig_id, }) return action @@ -133,53 +128,3 @@ class StockMoveLocationWizard(models.TransientModel): return { "type": "ir.action.do_nothing", } - - def _get_inventory_lines_values(self, inventory): - self.ensure_one() - lines = [] - for wizard_line in self.stock_move_location_line_ids: - lines.append({ - 'product_id': wizard_line.product_id.id, - 'product_uom_id': wizard_line.product_uom_id.id, - 'prod_lot_id': wizard_line.lot_id.id, - 'product_qty': self._get_available_quantity(wizard_line), - 'inventory_id': inventory.id, - 'location_id': self.origin_location_id.id, - }) - return lines - - def set_inventory_lines(self, inventory): - inventory_line_obj = self.env["stock.inventory.line"] - for line_vals in self._get_inventory_lines_values(inventory): - inventory_line_obj.create(line_vals) - - def _get_available_quantity(self, line): - """We check here if the actual amount changed in the stock. - - We don't care about the reservations but we do care about not moving - more than exists.""" - if not line.product_id: - return 0 - # switched to sql here to improve performance and lower db queries - self.env.cr.execute(self._get_specific_quants_sql(line)) - available_qty = self.env.cr.fetchone()[0] - if available_qty < line.move_quantity: - return available_qty - return line.move_quantity - - def _get_specific_quants_sql(self, line): - lot = "AND lot_id = {}".format(line.lot_id.id) - if not line.lot_id: - lot = "AND lot_id is null" - return """ - SELECT sum(quantity) - FROM stock_quant - WHERE location_id = {location} - {lot} - AND product_id = {product} - GROUP BY location_id, product_id, lot_id - """.format( - location=line.origin_location_id.id, - product=line.product_id.id, - lot=lot, - ) diff --git a/stock_move_location/wizard/stock_move_location.xml b/stock_move_location/wizard/stock_move_location.xml index e3d6587a7..263366e1d 100755 --- a/stock_move_location/wizard/stock_move_location.xml +++ b/stock_move_location/wizard/stock_move_location.xml @@ -29,7 +29,8 @@ diff --git a/stock_move_location/wizard/stock_move_location_line.py b/stock_move_location/wizard/stock_move_location_line.py index 07a0dac94..b05ecae98 100644 --- a/stock_move_location/wizard/stock_move_location_line.py +++ b/stock_move_location/wizard/stock_move_location_line.py @@ -14,10 +14,12 @@ class StockMoveLocationWizardLine(models.TransientModel): string="Move location Wizard", comodel_name="wiz.stock.move.location", ondelete="cascade", + required=True, ) product_id = fields.Many2one( string="Product", comodel_name="product.product", + required=True, ) origin_location_id = fields.Many2one( string='Origin Location', @@ -56,3 +58,54 @@ class StockMoveLocationWizardLine(models.TransientModel): raise ValidationError(_( "Move quantity can not exceed max quantity or be negative" )) + + def create_move_lines(self, picking): + for line in self: + self.env["stock.move.line"].create( + self._get_move_line_values(line, picking) + ) + return True + + def _get_move_line_values(self, line, picking): + return { + "product_id": line.product_id.id, + "lot_id": line.lot_id.id, + "location_id": line.origin_location_id.id, + "location_dest_id": line.destination_location_id.id, + "qty_done": line._get_available_quantity(), + "product_uom_id": line.product_uom_id.id, + "picking_id": picking.id, + } + + def _get_available_quantity(self): + """We check here if the actual amount changed in the stock. + + We don't care about the reservations but we do care about not moving + more than exists.""" + self.ensure_one() + if not self.product_id: + return 0 + # switched to sql here to improve performance and lower db queries + self.env.cr.execute(self._get_specific_quants_sql()) + available_qty = self.env.cr.fetchone()[0] + if available_qty < self.move_quantity: + return available_qty + return self.move_quantity + + def _get_specific_quants_sql(self): + self.ensure_one() + lot = "AND lot_id = {}".format(self.lot_id.id) + if not self.lot_id: + lot = "AND lot_id is null" + return """ + SELECT sum(quantity) + FROM stock_quant + WHERE location_id = {location} + {lot} + AND product_id = {product} + GROUP BY location_id, product_id, lot_id + """.format( + location=self.origin_location_id.id, + product=self.product_id.id, + lot=lot, + )