diff --git a/stock_vertical_lift_empty_tray_check/README.rst b/stock_vertical_lift_empty_tray_check/README.rst new file mode 100644 index 000000000..4a5d94e60 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/README.rst @@ -0,0 +1,90 @@ +============================== +Vertical Lift Empty Tray Check +============================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :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_empty_tray_check + :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_empty_tray_check + :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 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +When a tray is released, and the system thinks it is empty, +it prompts the user to actually check that it is empty or not. +In any case, an inventory adjustment is done stating the +situation: posted to zero if the tray is actually empty, and +set to draft is it is not empty. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +General +~~~~~~~ + +In Inventory Settings, you must have activated the option: *Check Empty Tray* + +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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Carlos Serra-Toro + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_vertical_lift_empty_tray_check/__init__.py b/stock_vertical_lift_empty_tray_check/__init__.py new file mode 100644 index 000000000..d4b7188d6 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +from . import models diff --git a/stock_vertical_lift_empty_tray_check/__manifest__.py b/stock_vertical_lift_empty_tray_check/__manifest__.py new file mode 100644 index 000000000..3e3c2930c --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +{ + "name": "Vertical Lift Empty Tray Check", + "summary": "Checks if the tray is actually empty.", + "version": "13.0.1.1.0", + "category": "Stock", + "author": "Camptocamp, Odoo Community Association (OCA)", + "license": "AGPL-3", + "depends": ["stock", "stock_vertical_lift"], + "website": "https://github.com/OCA/stock-logistics-warehouse", + "data": [ + "views/res_config_setting_views.xml", + "views/vertical_lift_operation_pick_zero_check_views.xml", + ], + "installable": True, + "development_status": "Alpha", +} diff --git a/stock_vertical_lift_empty_tray_check/i18n/stock_vertical_lift_empty_tray_check.pot b/stock_vertical_lift_empty_tray_check/i18n/stock_vertical_lift_empty_tray_check.pot new file mode 100644 index 000000000..eeb8ca461 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/i18n/stock_vertical_lift_empty_tray_check.pot @@ -0,0 +1,94 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_vertical_lift_empty_tray_check +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model,name:stock_vertical_lift_empty_tray_check.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model.fields,field_description:stock_vertical_lift_empty_tray_check.field_vertical_lift_operation_pick_zero_check__create_uid +msgid "Created by" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model.fields,field_description:stock_vertical_lift_empty_tray_check.field_vertical_lift_operation_pick_zero_check__create_date +msgid "Created on" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model.fields,field_description:stock_vertical_lift_empty_tray_check.field_vertical_lift_operation_pick_zero_check__display_name +msgid "Display Name" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model.fields,field_description:stock_vertical_lift_empty_tray_check.field_vertical_lift_operation_pick_zero_check__id +msgid "ID" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model_terms:ir.ui.view,arch_db:stock_vertical_lift_empty_tray_check.res_config_settings_view_form +msgid "" +"If checked and the system thinks the vertical tray is\n" +" empty, the operator will be asked to explicitly check\n" +" if this is the case or not" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: code:addons/stock_vertical_lift_empty_tray_check/models/vertical_lift_operation_pick.py:0 +#, python-format +msgid "Is the tray empty?" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model.fields,field_description:stock_vertical_lift_empty_tray_check.field_vertical_lift_operation_pick_zero_check____last_update +msgid "Last Modified on" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model.fields,field_description:stock_vertical_lift_empty_tray_check.field_vertical_lift_operation_pick_zero_check__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model.fields,field_description:stock_vertical_lift_empty_tray_check.field_vertical_lift_operation_pick_zero_check__write_date +msgid "Last Updated on" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model,name:stock_vertical_lift_empty_tray_check.model_vertical_lift_operation_pick_zero_check +msgid "Make sure the tray location is empty" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model_terms:ir.ui.view,arch_db:stock_vertical_lift_empty_tray_check.vertical_lift_operation_pick_zero_check_view_form +msgid "Tray Empty" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model_terms:ir.ui.view,arch_db:stock_vertical_lift_empty_tray_check.vertical_lift_operation_pick_zero_check_view_form +msgid "Tray Not Empty" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model,name:stock_vertical_lift_empty_tray_check.model_vertical_lift_operation_pick +#: model:ir.model.fields,field_description:stock_vertical_lift_empty_tray_check.field_vertical_lift_operation_pick_zero_check__vertical_lift_operation_pick_id +msgid "Vertical Lift Operation Pick" +msgstr "" + +#. module: stock_vertical_lift_empty_tray_check +#: model:ir.model.fields,field_description:stock_vertical_lift_empty_tray_check.field_res_config_settings__vertical_lift_empty_tray_check +msgid "Vertical lift: Check Empty Tray" +msgstr "" diff --git a/stock_vertical_lift_empty_tray_check/models/__init__.py b/stock_vertical_lift_empty_tray_check/models/__init__.py new file mode 100644 index 000000000..18af90d40 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from . import res_config_settings +from . import vertical_lift_operation_pick +from . import vertical_lift_operation_pick_zero_check diff --git a/stock_vertical_lift_empty_tray_check/models/res_config_settings.py b/stock_vertical_lift_empty_tray_check/models/res_config_settings.py new file mode 100644 index 000000000..b780f51f1 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/models/res_config_settings.py @@ -0,0 +1,11 @@ +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + vertical_lift_empty_tray_check = fields.Boolean( + "Vertical lift: Check Empty Tray", + default=False, + config_parameter="vertical_lift_empty_tray_check", + ) diff --git a/stock_vertical_lift_empty_tray_check/models/vertical_lift_operation_pick.py b/stock_vertical_lift_empty_tray_check/models/vertical_lift_operation_pick.py new file mode 100644 index 000000000..ace54dc24 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/models/vertical_lift_operation_pick.py @@ -0,0 +1,46 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, models +from odoo.tools import float_is_zero + + +class VerticalLiftOperationPick(models.Model): + _inherit = "vertical.lift.operation.pick" + + def button_release(self): + """Release the operation, go to the next + + By default it asks the user to inspect visually if the tray is empty. + """ + icp = self.env["ir.config_parameter"].sudo() + tray_check = icp.get_param("vertical_lift_empty_tray_check") + skip_zero_quantity_check = self.env.context.get("skip_zero_quantity_check") + if not skip_zero_quantity_check and tray_check: + uom_rounding = self.product_id.uom_id.rounding + if float_is_zero(self.tray_qty, precision_rounding=uom_rounding): + return self._check_zero_quantity() + + return super().button_release() + + def _check_zero_quantity(self): + """Show the wizard to check for real-zero quantity.""" + view = self.env.ref( + "stock_vertical_lift_empty_tray_check." + "vertical_lift_operation_pick_zero_check_view_form" + ) + wizard_model = "vertical.lift.operation.pick.zero.check" + wizard = self.env[wizard_model].create( + {"vertical_lift_operation_pick_id": self.id} + ) + return { + "name": _("Is the tray empty?"), + "type": "ir.actions.act_window", + "view_mode": "form", + "target": "new", + "views": [(view.id, "form")], + "view_id": view.id, + "res_model": wizard_model, + "res_id": wizard.id, + "context": self.env.context, + } diff --git a/stock_vertical_lift_empty_tray_check/models/vertical_lift_operation_pick_zero_check.py b/stock_vertical_lift_empty_tray_check/models/vertical_lift_operation_pick_zero_check.py new file mode 100644 index 000000000..ff34ffcf8 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/models/vertical_lift_operation_pick_zero_check.py @@ -0,0 +1,87 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) + +from odoo import _, fields, models + + +class VerticalLiftOperationPickZeroCheck(models.TransientModel): + _name = "vertical.lift.operation.pick.zero.check" + _description = "Make sure the tray location is empty" + + vertical_lift_operation_pick_id = fields.Many2one("vertical.lift.operation.pick") + + def _get_data_from_operation(self): + """Return picking, location and product from the operation shuttle""" + operation = self.vertical_lift_operation_pick_id + + # If the move is split into several move lines, it is + # moved to another picking, being a backorder of the + # original one. We are always interested in the original + # picking that was processed at first, so if the picking + # is a backorder of another picking, we take that other one. + picking = operation.picking_id.backorder_id or operation.picking_id + location = operation.current_move_line_id.location_id + product = operation.product_id + return operation, picking, location, product + + def button_confirm_empty(self): + """User confirms the tray location is empty + + This is in accordance with what we expected, because we only + call this action if we think the location is empty. We create + an inventory adjustment that states that a zero-check was + done for this location.""" + operation, picking, location, product = self._get_data_from_operation() + inventory_name = _(f"Zero check in location: {location.complete_name}") + inventory = ( + self.env["stock.inventory"] + .sudo() + .create( + { + "name": inventory_name, + "product_ids": [(4, product.id)], + "location_ids": [(4, location.id)], + "line_ids": [ + ( + 0, + 0, + { + "product_id": product.id, + "product_qty": 0, + "theoretical_qty": 0, + "location_id": location.id, + }, + ), + ], + } + ) + ) + inventory.action_start() + inventory.action_validate() + + # Return to the execution of the release, + # but without checking again if the tray is empty. + return operation.with_context(skip_zero_quantity_check=True).button_release() + + def button_confirm_not_empty(self): + """User confirms the tray location is not empty + + This contradicts what we expected, because we only call this + action if we think the location is empty. We create a draft + inventory adjustment stating the mismatch. + """ + operation, picking, location, product = self._get_data_from_operation() + inventory_name = _( + f"{picking.name} zero check issue on location {location.complete_name}" + ) + self.env["stock.inventory"].sudo().create( + { + "name": inventory_name, + "product_ids": [(4, product.id)], + "location_ids": [(4, location.id)], + } + ) + + # Return to the execution of the release, + # but without checking again if the tray is empty. + return operation.with_context(skip_zero_quantity_check=True).button_release() diff --git a/stock_vertical_lift_empty_tray_check/readme/CONFIGURE.rst b/stock_vertical_lift_empty_tray_check/readme/CONFIGURE.rst new file mode 100644 index 000000000..546cb6842 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/readme/CONFIGURE.rst @@ -0,0 +1,4 @@ +General +~~~~~~~ + +In Inventory Settings, you must have activated the option: *Check Empty Tray* diff --git a/stock_vertical_lift_empty_tray_check/readme/CONTRIBUTORS.rst b/stock_vertical_lift_empty_tray_check/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..1d2f3d485 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Carlos Serra-Toro diff --git a/stock_vertical_lift_empty_tray_check/readme/DESCRIPTION.rst b/stock_vertical_lift_empty_tray_check/readme/DESCRIPTION.rst new file mode 100644 index 000000000..858f08c0b --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +When a tray is released, and the system thinks it is empty, +it prompts the user to actually check that it is empty or not. +In any case, an inventory adjustment is done stating the +situation: posted to zero if the tray is actually empty, and +set to draft is it is not empty. diff --git a/stock_vertical_lift_empty_tray_check/static/description/icon.png b/stock_vertical_lift_empty_tray_check/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_vertical_lift_empty_tray_check/static/description/icon.png differ diff --git a/stock_vertical_lift_empty_tray_check/static/description/index.html b/stock_vertical_lift_empty_tray_check/static/description/index.html new file mode 100644 index 000000000..1ab8336c0 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/static/description/index.html @@ -0,0 +1,440 @@ + + + + + + +Vertical Lift Empty Tray Check + + + +
+

Vertical Lift Empty Tray Check

+ + +

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

+

When a tray is released, and the system thinks it is empty, +it prompts the user to actually check that it is empty or not. +In any case, an inventory adjustment is done stating the +situation: posted to zero if the tray is actually empty, and +set to draft is it is not empty.

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

Configuration

+
+

General

+

In Inventory Settings, you must have activated the option: Check Empty Tray

+
+
+
+

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.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

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.

+

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

+
+
+
+ + diff --git a/stock_vertical_lift_empty_tray_check/tests/__init__.py b/stock_vertical_lift_empty_tray_check/tests/__init__.py new file mode 100644 index 000000000..b4a9152b6 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/tests/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +from . import test_pick diff --git a/stock_vertical_lift_empty_tray_check/tests/test_pick.py b/stock_vertical_lift_empty_tray_check/tests/test_pick.py new file mode 100644 index 000000000..b0fed13d6 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/tests/test_pick.py @@ -0,0 +1,84 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) + +from odoo.addons.stock_vertical_lift.tests.common import VerticalLiftCase + + +class TestPick(VerticalLiftCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.picking_out = cls.env.ref( + "stock_vertical_lift.stock_picking_out_demo_vertical_lift_1" + ) + cls.env["ir.config_parameter"].sudo().set_param( + "vertical_lift_empty_tray_check", True + ) + + def _test_location_empty_common(self, operation, tray_is_empty): + """Common part for tests checking the tray location is empty + + Returns the new inventory adjustment created.""" + self.assertEqual(operation.state, "scan_destination") + move_line = operation.current_move_line_id + customers_location = self.env.ref("stock.stock_location_customers") + customers_location.barcode = "CUSTOMERS" + operation.on_barcode_scanned(customers_location.barcode) + self.assertEqual(move_line.location_dest_id, customers_location) + self.assertEqual(operation.state, "save") + operation.button_save() + self.assertEqual(operation.state, "release") + self.assertEqual(operation.tray_qty, 0) + + old_inventories = self.env["stock.inventory"].search([]) + + res_dict = operation.button_release() + wizard = self.env[(res_dict.get("res_model"))].browse(res_dict.get("res_id")) + wizard = wizard.with_context( + active_id=operation.id, active_model=operation._name + ) + if tray_is_empty: + wizard.button_confirm_empty() + else: + wizard.button_confirm_not_empty() + + new_inventory = self.env["stock.inventory"].search([]) - old_inventories + return new_inventory + + def test_location_empty_is_empty(self): + """ Location is indicated as being empty, and it is""" + operation = self._open_screen("pick") + tray_location = operation.tray_location_id + tray_product = operation.current_move_line_id.product_id + inventory = self._test_location_empty_common(operation, tray_is_empty=True) + + self.assertEqual(len(inventory), 1) + self.assertEqual(inventory.state, "done") + self.assertEqual( + inventory.name, + "Zero check in location: {}".format(tray_location.complete_name), + ) + self.assertEqual(len(inventory.line_ids), 1) + self.assertEqual(inventory.line_ids[0].product_id, tray_product) + self.assertEqual(inventory.line_ids[0].location_id, tray_location) + self.assertEqual(inventory.line_ids[0].product_qty, 0) + self.assertEqual(inventory.line_ids[0].theoretical_qty, 0) + + def test_location_empty_is_not_empty(self): + """ Location is indicated as being empty, but it is not. + """ + operation = self._open_screen("pick") + tray_location = operation.tray_location_id + tray_product = operation.current_move_line_id.product_id + inventory = self._test_location_empty_common(operation, tray_is_empty=False) + self.assertEqual(len(inventory), 1) + self.assertEqual(inventory.state, "draft") + self.assertEqual( + inventory.name, + "{} zero check issue on location {}".format( + self.picking_out.name, tray_location.complete_name, + ), + ) + self.assertEqual(inventory.product_ids, tray_product) + self.assertEqual(inventory.location_ids, tray_location) diff --git a/stock_vertical_lift_empty_tray_check/views/res_config_setting_views.xml b/stock_vertical_lift_empty_tray_check/views/res_config_setting_views.xml new file mode 100644 index 000000000..06b0e2c86 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/views/res_config_setting_views.xml @@ -0,0 +1,31 @@ + + + + + res.config.settings.view.form.inherit.stock + res.config.settings + + + + +
+
+ +
+
+
+
+
+
+
+
+
diff --git a/stock_vertical_lift_empty_tray_check/views/vertical_lift_operation_pick_zero_check_views.xml b/stock_vertical_lift_empty_tray_check/views/vertical_lift_operation_pick_zero_check_views.xml new file mode 100644 index 000000000..12395b266 --- /dev/null +++ b/stock_vertical_lift_empty_tray_check/views/vertical_lift_operation_pick_zero_check_views.xml @@ -0,0 +1,34 @@ + + + + + vertical.lift.operation.pick.zero.check.view.form + vertical.lift.operation.pick.zero.check + +
+
+
+
+
+
+
+