diff --git a/setup/stock_package_autoload/odoo/addons/stock_package_autoload b/setup/stock_package_autoload/odoo/addons/stock_package_autoload new file mode 120000 index 000000000000..67573195b09d --- /dev/null +++ b/setup/stock_package_autoload/odoo/addons/stock_package_autoload @@ -0,0 +1 @@ +../../../../stock_package_autoload \ No newline at end of file diff --git a/setup/stock_package_autoload/setup.py b/setup/stock_package_autoload/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/stock_package_autoload/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_package_autoload/README.rst b/stock_package_autoload/README.rst new file mode 100644 index 000000000000..a66fd4655b46 --- /dev/null +++ b/stock_package_autoload/README.rst @@ -0,0 +1,86 @@ +====================== +Stock Package Autoload +====================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:69b0a48bbc64d618505cdad031811c2a8e87a47821b73c1d6b6113126f8d26ae + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |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/16.0/stock_package_autoload + :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-16-0/stock-logistics-warehouse-16-0-stock_package_autoload + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-warehouse&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to automatically add the content of a package to each Transfer line. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +On a Transfer in "ready" state, click on the 'Detailed Operations' button on one of the lines. + +You can select a package and automatically add its content to the transfer. +Lots with the same serial cannot be added more than once + +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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* PyTech SRL + +Contributors +~~~~~~~~~~~~ + +* `PyTech-SRL `_: + + * Sebastiano Picchi + +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_package_autoload/__init__.py b/stock_package_autoload/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/stock_package_autoload/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_package_autoload/__manifest__.py b/stock_package_autoload/__manifest__.py new file mode 100644 index 000000000000..ef08217cbc84 --- /dev/null +++ b/stock_package_autoload/__manifest__.py @@ -0,0 +1,20 @@ +{ + "name": "Stock Package Autoload", + "summary": """ + Select a package to add its content to a transfer line + """, + "version": "16.0.1.0.0", + "author": "PyTech SRL, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "category": "Warehouse Management", + "depends": [ + "stock", + ], + "data": [ + "views/stock_move_view.xml", + ], + "demo": [], + "license": "AGPL-3", + "installable": True, + "application": False, +} diff --git a/stock_package_autoload/models/__init__.py b/stock_package_autoload/models/__init__.py new file mode 100644 index 000000000000..6bda2d2428e0 --- /dev/null +++ b/stock_package_autoload/models/__init__.py @@ -0,0 +1 @@ +from . import stock_move diff --git a/stock_package_autoload/models/stock_move.py b/stock_package_autoload/models/stock_move.py new file mode 100644 index 000000000000..23b32b21e24f --- /dev/null +++ b/stock_package_autoload/models/stock_move.py @@ -0,0 +1,69 @@ +from odoo import api, fields, models + + +class StockMove(models.Model): + _inherit = "stock.move" + + package_domain = fields.Binary( + compute="_compute_package_domain", + readonly=True, + store=False, + ) + load_products_from_package_id = fields.Many2one( + "stock.quant.package", + string="Add package contents", + help="Autoresets after use", + ) + + def _package_domain(self): + self.ensure_one() + to_return = ( + [("quant_ids.product_id", "=", self.product_id.id)] + if self.product_id + else [] + ) + return to_return + + def _compute_package_domain(self): + """ + There's no need to compute this field if the current user doesn't have the + necessary group + """ + if not self.env.user.has_group("stock.group_tracking_lot"): + self.write({"package_domain": "[]"}) + return + for sm in self: + sm.package_domain = sm._package_domain() + + @api.onchange("load_products_from_package_id") + def _onchange_load_products_from_package_id(self): + """Automatically load all items contained in the selected package. + Once the items have been added, the package is deleted. + The same serials cannot be selected more than once. + """ + current_lots = self.move_line_ids.mapped("lot_id") + product_quants = self.load_products_from_package_id.quant_ids.filtered( + lambda q, lots=current_lots: q.lot_id not in lots + ) + common_line_data = { + "move_id": self.id, + "tracking": self.has_tracking, + "product_id": self.product_id.id, + "package_id": self.load_products_from_package_id.id, + "location_id": self.location_id.id, + "location_dest_id": self.location_dest_id.id, + "company_id": self.company_id.id, + } + data_list = [] + for quant in product_quants: + data = common_line_data.copy() + data.update( + { + "qty_done": quant.quantity, + "product_uom_id": quant.product_uom_id.id, + "lot_id": quant.lot_id.id, + } + ) + data_list.append(data) + self.env["stock.move.line"].create(data_list) + self.load_products_from_package_id = False diff --git a/stock_package_autoload/readme/CONTRIBUTORS.rst b/stock_package_autoload/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..850924ee638c --- /dev/null +++ b/stock_package_autoload/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `PyTech-SRL `_: + + * Sebastiano Picchi diff --git a/stock_package_autoload/readme/DESCRIPTION.rst b/stock_package_autoload/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..49a36689e4bd --- /dev/null +++ b/stock_package_autoload/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module allows to automatically add the content of a package to each Transfer line. diff --git a/stock_package_autoload/readme/USAGE.rst b/stock_package_autoload/readme/USAGE.rst new file mode 100644 index 000000000000..98b1aad6c582 --- /dev/null +++ b/stock_package_autoload/readme/USAGE.rst @@ -0,0 +1,4 @@ +On a Transfer in "ready" state, click on the 'Detailed Operations' button on one of the lines. + +You can select a package and automatically add its content to the transfer. +Lots with the same serial cannot be added more than once diff --git a/stock_package_autoload/static/description/index.html b/stock_package_autoload/static/description/index.html new file mode 100644 index 000000000000..1cd7b9df70ae --- /dev/null +++ b/stock_package_autoload/static/description/index.html @@ -0,0 +1,436 @@ + + + + + +Stock Package Autoload + + + +
+

Stock Package Autoload

+ + +

Beta License: AGPL-3 OCA/stock-logistics-warehouse Translate me on Weblate Try me on Runboat

+

This module allows to automatically add the content of a package to each Transfer line.

+

Table of contents

+ +
+

Usage

+

On a Transfer in “ready” state, click on the ‘Detailed Operations’ button on one of the lines.

+

You can select a package and automatically add its content to the transfer. +Lots with the same serial cannot be added more than once

+
+
+

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 to smash it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • PyTech SRL
  • +
+
+
+

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_package_autoload/tests/__init__.py b/stock_package_autoload/tests/__init__.py new file mode 100644 index 000000000000..65badf35345e --- /dev/null +++ b/stock_package_autoload/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_package_autoload diff --git a/stock_package_autoload/tests/test_stock_package_autoload.py b/stock_package_autoload/tests/test_stock_package_autoload.py new file mode 100644 index 000000000000..c866417c0aa5 --- /dev/null +++ b/stock_package_autoload/tests/test_stock_package_autoload.py @@ -0,0 +1,108 @@ +from odoo.tests.common import TransactionCase, tagged + + +@tagged("post_install", "-at_install") +class TestStockPackageAutoload(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.ProductProduct = cls.env["product.product"] + cls.StockMove = cls.env["stock.move"] + cls.StockMoveLine = cls.env["stock.move.line"] + cls.StockPicking = cls.env["stock.picking"] + cls.StockProductionLot = cls.env["stock.lot"] + cls.StockQuantPackage = cls.env["stock.quant.package"] + + cls.company = cls.env.company + cls.uom_unit = cls.env.ref("uom.product_uom_unit") + cls.location = cls.env.ref("stock.stock_location_stock") + cls.location_dest = cls.env.ref("stock.stock_location_customers") + cls.product = cls.ProductProduct.create( + { + "name": "Test Product With Serial", + "type": "product", + "tracking": "serial", + } + ) + + n_lots = 6 + cls.lots = cls.StockProductionLot.create( + [ + { + "name": "0" * 4 + str(i), + "product_id": cls.product.id, + "company_id": cls.company.id, + } + for i in range(1, n_lots + 1) + ] + ) + + cls.package = cls.StockQuantPackage.create( + { + "name": "PACK000014", + "quant_ids": [ + ( + 0, + 0, + { + "product_id": cls.product.id, + "quantity": 1, + "product_uom_id": cls.uom_unit, + "location_id": cls.location.id, + "lot_id": lot.id, + }, + ) + for lot in cls.lots[:3] + ], + } + ) + + def test_autoload_package(self): + picking_to_package = self.StockPicking.create( + { + "partner_id": self.env.ref("base.res_partner_address_15").id, + "picking_type_id": self.env.ref("stock.picking_type_out").id, + "location_id": self.location.id, + "location_dest_id": self.location_dest.id, + "company_id": self.company.id, + "move_line_ids_without_package": [ + ( + 0, + 0, + { + "product_id": self.product.id, + "reserved_uom_qty": 3, + "product_uom_id": self.uom_unit.id, + "location_id": self.location.id, + "location_dest_id": self.location_dest.id, + "company_id": self.env.company.id, + }, + ) + ], + } + ) + picking_to_package.action_confirm() + move = picking_to_package.move_ids_without_package + package_domain = self.StockQuantPackage.search(move._package_domain()) + self.assertEqual(package_domain, self.package) + move.load_products_from_package_id = self.package + move._onchange_load_products_from_package_id() + self.assertFalse(move.load_products_from_package_id) + n_move_lines = len(move.move_line_ids) + self.assertEqual( + move.move_line_ids.mapped("lot_id"), self.package.quant_ids.mapped("lot_id") + ) + # delete a line + move.move_line_ids[1].unlink() + self.assertNotEqual( + move.move_line_ids.mapped("lot_id"), self.package.quant_ids.mapped("lot_id") + ) + self.assertLess(len(move.move_line_ids), n_move_lines) + # by selecting the same package again, only the missing serial will be added to + # the move lines + move.load_products_from_package_id = self.package + move._onchange_load_products_from_package_id() + self.assertEqual(n_move_lines, len(move.move_line_ids)) + self.assertEqual( + move.move_line_ids.mapped("lot_id"), self.package.quant_ids.mapped("lot_id") + ) diff --git a/stock_package_autoload/views/stock_move_view.xml b/stock_package_autoload/views/stock_move_view.xml new file mode 100644 index 000000000000..ca84819af175 --- /dev/null +++ b/stock_package_autoload/views/stock_move_view.xml @@ -0,0 +1,21 @@ + + + + stock.move.operations.form + stock.move + + + + + + + + + + +