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

+

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
+
+
+
+
+
The development of this module has been financially supported by:
+
-
+
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.
-
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)