diff --git a/stock_vertical_lift/README.rst b/stock_vertical_lift/README.rst index cb8943930..fa7bf4b05 100644 --- a/stock_vertical_lift/README.rst +++ b/stock_vertical_lift/README.rst @@ -14,13 +14,13 @@ Vertical Lift :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github - :target: https://github.com/OCA/stock-logistics-warehouse/tree/13.0/stock_vertical_lift + :target: https://github.com/OCA/stock-logistics-warehouse/tree/14.0/stock_vertical_lift :alt: OCA/stock-logistics-warehouse .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-13-0/stock-logistics-warehouse-13-0-stock_vertical_lift + :target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-14-0/stock-logistics-warehouse-14-0-stock_vertical_lift :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/153/13.0 + :target: https://runbot.odoo-community.org/runbot/153/14.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -121,7 +121,7 @@ Bug Tracker Bugs are tracked on `GitHub 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -138,6 +138,17 @@ Contributors * Guewen Baconnier +Trobz + +* Dung Tran + +Other credits +~~~~~~~~~~~~~ + +The development of this module has been financially supported by: + +* Camptocamp + Maintainers ~~~~~~~~~~~ @@ -151,6 +162,6 @@ 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. -This module is part of the `OCA/stock-logistics-warehouse `_ project on GitHub. +This module is part of the `OCA/stock-logistics-warehouse `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_vertical_lift/__init__.py b/stock_vertical_lift/__init__.py index f7209b171..b6de22769 100644 --- a/stock_vertical_lift/__init__.py +++ b/stock_vertical_lift/__init__.py @@ -1,2 +1,3 @@ from . import models from . import controllers +from . import wizards diff --git a/stock_vertical_lift/__manifest__.py b/stock_vertical_lift/__manifest__.py index c201a9b10..7369346ea 100644 --- a/stock_vertical_lift/__manifest__.py +++ b/stock_vertical_lift/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Vertical Lift", "summary": "Provides the core for integration with Vertical Lifts", - "version": "13.0.1.2.1", + "version": "14.0.1.0.0", "category": "Stock", "author": "Camptocamp, Odoo Community Association (OCA)", "license": "AGPL-3", diff --git a/stock_vertical_lift/demo/stock_location_demo.xml b/stock_vertical_lift/demo/stock_location_demo.xml index be6afec8f..0a85cfbf9 100644 --- a/stock_vertical_lift/demo/stock_location_demo.xml +++ b/stock_vertical_lift/demo/stock_location_demo.xml @@ -32,7 +32,7 @@ internal @@ -102,7 +102,7 @@ internal diff --git a/stock_vertical_lift/models/stock_location.py b/stock_vertical_lift/models/stock_location.py index 56e2dc07f..7a5d26f94 100644 --- a/stock_vertical_lift/models/stock_location.py +++ b/stock_vertical_lift/models/stock_location.py @@ -10,7 +10,7 @@ class StockLocation(models.Model): vertical_lift_location = fields.Boolean( "Is a Vertical Lift View Location?", default=False, - help="Check this box to use it as the view for Vertical" " Lift Shuttles.", + help="Check this box to use it as the view for Vertical Lift Shuttles.", ) vertical_lift_kind = fields.Selection( selection=[ diff --git a/stock_vertical_lift/models/vertical_lift_operation_base.py b/stock_vertical_lift/models/vertical_lift_operation_base.py index 682d35111..216ac921c 100644 --- a/stock_vertical_lift/models/vertical_lift_operation_base.py +++ b/stock_vertical_lift/models/vertical_lift_operation_base.py @@ -12,6 +12,7 @@ _logger = logging.getLogger(__name__) # The following methods have been copied from 'shopfloor' module (OCA/wms) +# https://github.com/OCA/wms/blob/14.0/shopfloor/models/stock_move.py#L19 # TODO: we should move them in a generic module @@ -22,8 +23,11 @@ def split_other_move_lines(move, move_lines): other_move_lines = move.move_line_ids - move_lines if other_move_lines or move.state == "partially_available": qty_to_split = move.product_uom_qty - sum(move_lines.mapped("product_uom_qty")) - backorder_move_id = move._split(qty_to_split) - backorder_move = move.browse(backorder_move_id) + backorder_move_vals = move._split(qty_to_split) + backorder_move = move.create(backorder_move_vals) + if not backorder_move: + return False + backorder_move._action_confirm(merge=False) backorder_move.move_line_ids = other_move_lines backorder_move._recompute_state() backorder_move._action_assign() @@ -43,7 +47,7 @@ def extract_and_action_done(move): # in their own move (which will be then 'confirmed') partial_moves = move.filtered(lambda m: m.state == "partially_available") for partial_move in partial_moves: - partial_move.split_other_move_lines(partial_move.move_line_ids) + split_other_move_lines(partial_move, partial_move.move_line_ids) # Process assigned moves moves = move.filtered(lambda m: m.state == "assigned") if not moves: @@ -77,7 +81,7 @@ def extract_and_action_done(move): ) new_picking.action_assign() assert new_picking.state == "assigned" - new_picking.action_done() + new_picking._action_done() return True @@ -304,7 +308,7 @@ class VerticalLiftOperationBase(models.AbstractModel): def _render_product_packagings(self, product): if not product: return "" - return self.env["ir.qweb"].render( + return self.env["ir.qweb"]._render( "stock_vertical_lift.packagings", self._prepare_values_for_product_packaging(product), ) diff --git a/stock_vertical_lift/models/vertical_lift_shuttle.py b/stock_vertical_lift/models/vertical_lift_shuttle.py index 7ca2aa1bb..3ec8c73a5 100644 --- a/stock_vertical_lift/models/vertical_lift_shuttle.py +++ b/stock_vertical_lift/models/vertical_lift_shuttle.py @@ -138,6 +138,7 @@ class VerticalLiftShuttle(models.Model): This method does nothing, override to match your communication protocol.""" + pass # noqa def _operation_for_mode(self): model = self._model_for_mode[self.mode] @@ -258,19 +259,3 @@ class VerticalLiftShuttle(models.Model): """ # XXX do we want to do something special in the notification? self._operation_for_mode()._send_notification_refresh() - - -class VerticalLiftShuttleManualBarcode(models.TransientModel): - _name = "vertical.lift.shuttle.manual.barcode" - _description = "Action to input a barcode" - - barcode = fields.Char(string="Barcode") - - def button_save(self): - active_id = self.env.context.get("active_id") - model = self.env.context.get("active_model") - record = self.env[model].browse(active_id).exists() - if not record: - return - if self.barcode: - record.on_barcode_scanned(self.barcode) diff --git a/stock_vertical_lift/readme/CONTRIBUTORS.rst b/stock_vertical_lift/readme/CONTRIBUTORS.rst index 48286263c..36ac008db 100644 --- a/stock_vertical_lift/readme/CONTRIBUTORS.rst +++ b/stock_vertical_lift/readme/CONTRIBUTORS.rst @@ -1 +1,5 @@ * Guewen Baconnier + +Trobz + +* Dung Tran diff --git a/stock_vertical_lift/readme/CREDITS.rst b/stock_vertical_lift/readme/CREDITS.rst new file mode 100644 index 000000000..f5cc070c7 --- /dev/null +++ b/stock_vertical_lift/readme/CREDITS.rst @@ -0,0 +1,3 @@ +The development of this module has been financially supported by: + +* Camptocamp diff --git a/stock_vertical_lift/security/ir.model.access.csv b/stock_vertical_lift/security/ir.model.access.csv index 1b6621da0..a0cc73ad4 100644 --- a/stock_vertical_lift/security/ir.model.access.csv +++ b/stock_vertical_lift/security/ir.model.access.csv @@ -5,3 +5,4 @@ access_vertical_lift_operation_pick_stock_user,access_vertical_lift_operation_pi access_vertical_lift_operation_put_stock_user,access_vertical_lift_operation_put stock user,model_vertical_lift_operation_put,stock.group_stock_user,1,1,1,1 access_vertical_lift_operation_inventory_stock_user,access_vertical_lift_operation_inventory stock user,model_vertical_lift_operation_inventory,stock.group_stock_user,1,1,1,1 access_vertical_lift_command,vertical_lift_command,model_vertical_lift_command,base.group_user,1,0,0,0 +access_vertical_lift_shuttle_manual_barcode,access_vertical_lift_shuttle_manual_barcode wizard,model_vertical_lift_shuttle_manual_barcode,stock.group_stock_user,1,1,1,0 diff --git a/stock_vertical_lift/static/description/index.html b/stock_vertical_lift/static/description/index.html index c2394ad2c..42923d779 100644 --- a/stock_vertical_lift/static/description/index.html +++ b/stock_vertical_lift/static/description/index.html @@ -367,7 +367,7 @@ ul.auto-toc { !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Alpha License: AGPL-3 OCA/stock-logistics-warehouse Translate me on Weblate Try me on Runbot

+

Alpha License: AGPL-3 OCA/stock-logistics-warehouse Translate me on Weblate Try me on Runbot

Add configuration and dedicated screens to work with Vertical Lift systems (such as Kardex Remstar, Modula, …). Drivers for controlling the lifts physically must be added by additional addons.

@@ -395,7 +395,8 @@ Only for development or testing purpose, do not use in production.
  • Credits
  • @@ -479,7 +480,7 @@ makes sense)

    Bugs are tracked on GitHub 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.

    +feedback.

    Do not contact contributors directly about support or help with technical issues.

    @@ -495,15 +496,26 @@ If you spotted it first, help us smashing it by providing a detailed and welcome +

    Trobz

    + +
    +
    +

    Other credits

    +

    The development of this module has been financially supported by:

    +
      +
    • Camptocamp
    • +
    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association

    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.

    -

    This module is part of the OCA/stock-logistics-warehouse project on GitHub.

    +

    This module is part of the OCA/stock-logistics-warehouse project on GitHub.

    You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

    diff --git a/stock_vertical_lift/tests/__init__.py b/stock_vertical_lift/tests/__init__.py index dd10460b3..d60c8112e 100644 --- a/stock_vertical_lift/tests/__init__.py +++ b/stock_vertical_lift/tests/__init__.py @@ -1,3 +1,4 @@ +from . import test_lift_command from . import test_location from . import test_inventory from . import test_pick diff --git a/stock_vertical_lift/tests/common.py b/stock_vertical_lift/tests/common.py index e87853267..2a069fd86 100644 --- a/stock_vertical_lift/tests/common.py +++ b/stock_vertical_lift/tests/common.py @@ -158,7 +158,7 @@ class VerticalLiftCase(common.LocationTrayTypeCase): # for the test, we'll consider all the lines has been delivered for move_line in move_lines: move_line.qty_done = move_line.product_qty - move_lines.picking_id.action_done() + move_lines.picking_id._action_done() # release, no further operation in queue operation = self.shuttle._operation_for_mode() # the release button can be used only in the state... release diff --git a/stock_vertical_lift/tests/test_inventory.py b/stock_vertical_lift/tests/test_inventory.py index b22d4661d..05f916d9d 100644 --- a/stock_vertical_lift/tests/test_inventory.py +++ b/stock_vertical_lift/tests/test_inventory.py @@ -23,6 +23,23 @@ class TestInventory(VerticalLiftCase): self.assertEqual(action["res_model"], "vertical.lift.operation.inventory") self.assertEqual(action["res_id"], operation.id) + def test_inventory_actions(self): + self.shuttle.switch_inventory() + action = self.shuttle.action_menu() + self.assertEqual(action["type"], "ir.actions.act_window") + self.assertEqual(action["res_model"], "vertical.lift.shuttle") + self.assertEqual(action["res_id"], self.shuttle.id) + + action = self.shuttle.action_back_to_settings() + self.assertEqual(action["type"], "ir.actions.act_window") + self.assertEqual(action["res_model"], "vertical.lift.shuttle") + self.assertEqual(action["res_id"], 0) + + action = self.shuttle.action_manual_barcode() + self.assertEqual(action["type"], "ir.actions.act_window") + self.assertEqual(action["res_model"], "vertical.lift.shuttle.manual.barcode") + self.assertEqual(action["name"], "Barcode") + def test_inventory_count_ops(self): self._update_qty_in_location(self.location_1a_x1y1, self.product_socks, 10) self._update_qty_in_location(self.location_1a_x2y1, self.product_recovery, 10) @@ -91,6 +108,24 @@ class TestInventory(VerticalLiftCase): self.assertTrue(inventory.line_ids.vertical_lift_done) self.assertEqual(inventory.state, "done") + def test_confirm_wrong_quantity(self): + self._update_qty_in_location(self.location_1a_x1y1, self.product_socks, 10) + inventory = self._create_inventory( + [(self.location_1a_x1y1, self.product_socks)] + ) + operation = self._open_screen("inventory") + line = operation.current_inventory_line_id + self.assertEqual(line, inventory.line_ids) + + operation.quantity_input = 12.0 + operation.button_save() + self.assertEqual(operation.last_quantity_input, 12.0) + self.assertEqual(operation.quantity_input, 0.0) + self.assertEqual(operation.state, "confirm_wrong_quantity") + self.assertEqual(operation.current_inventory_line_id, line) + operation.button_save() + self.assertEqual(operation.state, "quantity") + def test_inventory_next_line(self): self._update_qty_in_location(self.location_1a_x1y1, self.product_socks, 10) self._update_qty_in_location(self.location_1a_x2y1, self.product_recovery, 10) @@ -113,3 +148,19 @@ class TestInventory(VerticalLiftCase): self.assertEqual(operation.current_inventory_line_id, remaining_line) self.assertEqual(operation.last_quantity_input, 0.0) self.assertEqual(operation.quantity_input, 0.0) + + def test_inventory_locations(self): + self.shuttle.switch_inventory() + opr_inventory = self.shuttle._operation_for_mode() + opr_inventory._compute_tray_data() + opr_inventory._compute_product_packagings() + self.assertEqual(opr_inventory.product_packagings, "") + opr_inventory._compute_tray_qty() + self.assertEqual(opr_inventory.tray_qty, 0.0) + + self._update_qty_in_location(self.location_1a_x1y1, self.product_socks, 10) + self._create_inventory([(self.location_1a_x1y1, self.product_socks)]) + self._open_screen("inventory") + opr_inventory._compute_product_packagings() + opr_inventory._compute_tray_qty() + self.assertEqual(opr_inventory.tray_qty, 10) diff --git a/stock_vertical_lift/tests/test_lift_command.py b/stock_vertical_lift/tests/test_lift_command.py new file mode 100644 index 000000000..a7940defa --- /dev/null +++ b/stock_vertical_lift/tests/test_lift_command.py @@ -0,0 +1,25 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import exceptions +from odoo.tools import mute_logger + +from .common import VerticalLiftCase + + +class TestLiftCommand(VerticalLiftCase): + def test_lift_commands(self): + self.shuttle.switch_inventory() + command_id = self.shuttle.command_ids[0] + message = "Unknown record" + method_name = "odoo.addons.stock_vertical_lift.models.vertical_lift_command" + with mute_logger(method_name): + with self.assertRaisesRegex(exceptions.UserError, message): + command_id.record_answer("0|test|1") + command_id.record_answer("0|{}|1".format(command_id.name)) + self.shuttle.command_ids.create( + { + "shuttle_id": self.shuttle.id, + "command": "0|test|1", + } + ) diff --git a/stock_vertical_lift/tests/test_location.py b/stock_vertical_lift/tests/test_location.py index 712436d73..a41ebe980 100644 --- a/stock_vertical_lift/tests/test_location.py +++ b/stock_vertical_lift/tests/test_location.py @@ -1,6 +1,8 @@ # Copyright 2019 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import exceptions + from .common import VerticalLiftCase @@ -25,6 +27,19 @@ class TestVerticalLiftLocation(VerticalLiftCase): all(location.vertical_lift_kind == "cell" for location in cells) ) + def test_fetch_vertical_lift_tray(self): + shuttles = self.vertical_lift_loc.child_ids + trays = shuttles.mapped("child_ids") + cells = trays.mapped("child_ids") + self.assertTrue(cells[0].button_fetch_vertical_lift_tray()) + message = "cell_location cannot be set when the location is a cell." + with self.assertRaisesRegex(ValueError, message): + cells[0].fetch_vertical_lift_tray(cells[0]) + message = "Cannot fetch a vertical lift tray on location" + with self.assertRaisesRegex(exceptions.UserError, message): + shuttles[0].fetch_vertical_lift_tray(cells[0]) + self.assertTrue(cells[0].button_release_vertical_lift_tray()) + def test_create_shuttle(self): # any location created directly under the view is a shuttle shuttle_loc = self.env["stock.location"].create( diff --git a/stock_vertical_lift/tests/test_pick.py b/stock_vertical_lift/tests/test_pick.py index e482f69da..6803a00b3 100644 --- a/stock_vertical_lift/tests/test_pick.py +++ b/stock_vertical_lift/tests/test_pick.py @@ -118,9 +118,16 @@ class TestPick(VerticalLiftCase): product1 = self.env.ref("stock_vertical_lift.product_running_socks") product2 = self.env.ref("stock_vertical_lift.product_recovery_socks") # cancel the picking from demo data to start from a clean state - self.env.ref( + picking_1 = self.env.ref( "stock_vertical_lift.stock_picking_out_demo_vertical_lift_1" - ).action_cancel() + ) + # If stock_picking_cancel_confirm is installed, we need to explicitly + # confirm the cancellation. + try: + picking_1.cancel_confirm = True + except AttributeError: + pass + picking_1.action_cancel() # ensure that we have stock in some cells, we'll put product1 # in the first Shuttle and product2 in the second @@ -181,6 +188,8 @@ class TestPick(VerticalLiftCase): def test_on_barcode_scanned(self): operation = self._open_screen("pick") self.assertEqual(operation.state, "scan_destination") + # Scan wrong one first for test coverage + operation.on_barcode_scanned("test") move_line = operation.current_move_line_id current_destination = move_line.location_dest_id stock_location = self.env.ref("stock.stock_location_stock") @@ -190,6 +199,9 @@ class TestPick(VerticalLiftCase): operation.on_barcode_scanned(stock_location.barcode) self.assertEqual(move_line.location_dest_id, stock_location) self.assertEqual(operation.state, "save") + # Done for test coverage + operation.button_save() + operation.on_barcode_scanned("test") def test_button_release(self): self._open_screen("pick") @@ -216,8 +228,8 @@ class TestPick(VerticalLiftCase): "selected": [expected_x, expected_y], # fmt: off 'cells': [ - [0, 0, 0, 0, 0, 0, 0, 0], - [1, 1, 1, 0, 0, 0, 0, 0], + [0, 0, 0, 0], + [1, 1, 1, 0], ] # fmt: on }, diff --git a/stock_vertical_lift/tests/test_put.py b/stock_vertical_lift/tests/test_put.py index 75f16e03b..4b383a6ea 100644 --- a/stock_vertical_lift/tests/test_put.py +++ b/stock_vertical_lift/tests/test_put.py @@ -32,6 +32,12 @@ class TestPut(VerticalLiftCase): ) def test_put_count_move_lines(self): + # If stock_picking_cancel_confirm is installed, we need to explicitly + # confirm the cancellation. + try: + self.picking_in.cancel_confirm = True + except AttributeError: + pass self.picking_in.action_cancel() put1 = self._create_simple_picking_in( self.product_socks, 10, self.location_1a_x1y1 diff --git a/stock_vertical_lift/wizards/__init__.py b/stock_vertical_lift/wizards/__init__.py new file mode 100644 index 000000000..d22e2b111 --- /dev/null +++ b/stock_vertical_lift/wizards/__init__.py @@ -0,0 +1 @@ +from . import vertical_lift_shuttle_manual_barcode diff --git a/stock_vertical_lift/wizards/vertical_lift_shuttle_manual_barcode.py b/stock_vertical_lift/wizards/vertical_lift_shuttle_manual_barcode.py new file mode 100644 index 000000000..f18a71bbc --- /dev/null +++ b/stock_vertical_lift/wizards/vertical_lift_shuttle_manual_barcode.py @@ -0,0 +1,20 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class VerticalLiftShuttleManualBarcode(models.TransientModel): + _name = "vertical.lift.shuttle.manual.barcode" + _description = "Action to input a barcode" + + barcode = fields.Char(string="Barcode") + + def button_save(self): + active_id = self.env.context.get("active_id") + model = self.env.context.get("active_model") + record = self.env[model].browse(active_id).exists() + if not record: + return + if self.barcode: + record.on_barcode_scanned(self.barcode)