From f3af4d4f9083cdf3ece56cc1d27493018e401e82 Mon Sep 17 00:00:00 2001 From: GuillemCForgeFlow Date: Tue, 16 May 2023 10:10:26 +0200 Subject: [PATCH] [ADD]stock_picking_orig_dest_link Adds the link between the origin and the destination pickings. --- .../odoo/addons/stock_picking_orig_dest_link | 1 + setup/stock_picking_orig_dest_link/setup.py | 6 ++ stock_picking_orig_dest_link/__init__.py | 2 + stock_picking_orig_dest_link/__manifest__.py | 18 ++++ stock_picking_orig_dest_link/hooks.py | 41 +++++++++ .../models/__init__.py | 1 + .../models/stock_picking.py | 51 +++++++++++ .../readme/CONTRIBUTORS.rst | 2 + .../readme/DESCRIPTION.rst | 5 ++ .../readme/ROADMAP.rst | 1 + .../tests/__init__.py | 1 + .../test_stock_picking_orig_dest_link.py | 87 +++++++++++++++++++ .../views/stock_picking_views.xml | 37 ++++++++ 13 files changed, 253 insertions(+) create mode 120000 setup/stock_picking_orig_dest_link/odoo/addons/stock_picking_orig_dest_link create mode 100644 setup/stock_picking_orig_dest_link/setup.py create mode 100644 stock_picking_orig_dest_link/__init__.py create mode 100644 stock_picking_orig_dest_link/__manifest__.py create mode 100644 stock_picking_orig_dest_link/hooks.py create mode 100644 stock_picking_orig_dest_link/models/__init__.py create mode 100644 stock_picking_orig_dest_link/models/stock_picking.py create mode 100644 stock_picking_orig_dest_link/readme/CONTRIBUTORS.rst create mode 100644 stock_picking_orig_dest_link/readme/DESCRIPTION.rst create mode 100644 stock_picking_orig_dest_link/readme/ROADMAP.rst create mode 100644 stock_picking_orig_dest_link/tests/__init__.py create mode 100644 stock_picking_orig_dest_link/tests/test_stock_picking_orig_dest_link.py create mode 100644 stock_picking_orig_dest_link/views/stock_picking_views.xml diff --git a/setup/stock_picking_orig_dest_link/odoo/addons/stock_picking_orig_dest_link b/setup/stock_picking_orig_dest_link/odoo/addons/stock_picking_orig_dest_link new file mode 120000 index 000000000..b6e454a90 --- /dev/null +++ b/setup/stock_picking_orig_dest_link/odoo/addons/stock_picking_orig_dest_link @@ -0,0 +1 @@ +../../../../stock_picking_orig_dest_link \ No newline at end of file diff --git a/setup/stock_picking_orig_dest_link/setup.py b/setup/stock_picking_orig_dest_link/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_picking_orig_dest_link/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_picking_orig_dest_link/__init__.py b/stock_picking_orig_dest_link/__init__.py new file mode 100644 index 000000000..a9b33fa5f --- /dev/null +++ b/stock_picking_orig_dest_link/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import pre_init_hook, post_init_hook diff --git a/stock_picking_orig_dest_link/__manifest__.py b/stock_picking_orig_dest_link/__manifest__.py new file mode 100644 index 000000000..2282821f7 --- /dev/null +++ b/stock_picking_orig_dest_link/__manifest__.py @@ -0,0 +1,18 @@ +# Copyright 2023 ForgeFlow S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "Stock Picking Origin Destination Link", + "summary": """ + This addon link the pickings with their respective Origin and Destination Pickings. + """, + "version": "13.0.1.0.0", + "author": "ForgeFlow, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "category": "Warehouse Management", + "license": "AGPL-3", + "depends": ["stock"], + "data": ["views/stock_picking_views.xml"], + "installable": True, + "pre_init_hook": "pre_init_hook", + "post_init_hook": "post_init_hook", +} diff --git a/stock_picking_orig_dest_link/hooks.py b/stock_picking_orig_dest_link/hooks.py new file mode 100644 index 000000000..cce6814f6 --- /dev/null +++ b/stock_picking_orig_dest_link/hooks.py @@ -0,0 +1,41 @@ +# Copyright 2023 ForgeFlow, S.L. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import logging + +from odoo import SUPERUSER_ID, api +from odoo.tools import sql + +_logger = logging.getLogger(__name__) + + +def pre_init_hook(cr): + _logger.info( + "Create temporary table to avoid the automatic launch of the compute method" + ) + if not sql.table_exists(cr, "stock_picking_orig_dest_rel"): + cr.execute("CREATE TABLE stock_picking_orig_dest_rel (temp INTEGER)") + + +def post_init_hook(cr, registry): + env = api.Environment(cr, SUPERUSER_ID, {}) + _logger.info("Dropping temporary table") + cr.execute("DROP TABLE stock_picking_orig_dest_rel") + _logger.info("Creating new table via ORM") + StockPicking = env["stock.picking"] + StockPicking._fields["orig_picking_ids"].update_db(StockPicking, False) + StockPicking._fields["dest_picking_ids"].update_db(StockPicking, False) + _logger.info("Filling Origin and Destination Picking relation table") + query = """ + WITH query AS ( + SELECT spo.id AS orig_picking_id, spd.id AS dest_picking_id + FROM stock_move_move_rel smml + JOIN stock_move smo ON smo.id = smml.move_orig_id + JOIN stock_move smd ON smd.id = smml.move_dest_id + JOIN stock_picking spo ON smo.picking_id = spo.id + JOIN stock_picking spd ON smd.picking_id = spd.id + GROUP BY spo.id, spd.id + ) + INSERT INTO stock_picking_orig_dest_rel (orig_picking_id, dest_picking_id) + SELECT * FROM query; + """ + cr.execute(query) diff --git a/stock_picking_orig_dest_link/models/__init__.py b/stock_picking_orig_dest_link/models/__init__.py new file mode 100644 index 000000000..ae4c27227 --- /dev/null +++ b/stock_picking_orig_dest_link/models/__init__.py @@ -0,0 +1 @@ +from . import stock_picking diff --git a/stock_picking_orig_dest_link/models/stock_picking.py b/stock_picking_orig_dest_link/models/stock_picking.py new file mode 100644 index 000000000..c2acfd24d --- /dev/null +++ b/stock_picking_orig_dest_link/models/stock_picking.py @@ -0,0 +1,51 @@ +# Copyright 2023 ForgeFlow S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models + + +class StockPicking(models.Model): + _inherit = "stock.picking" + + orig_picking_ids = fields.Many2many( + comodel_name="stock.picking", + relation="stock_picking_orig_dest_rel", + column1="dest_picking_id", + column2="orig_picking_id", + string="Origin Transfer/s", + compute="_compute_origin_dest_picking", + store=True, + readonly=True, + ) + dest_picking_ids = fields.Many2many( + comodel_name="stock.picking", + relation="stock_picking_orig_dest_rel", + column1="orig_picking_id", + column2="dest_picking_id", + string="Destination Transfer/s", + compute="_compute_origin_dest_picking", + store=True, + readonly=True, + ) + + def _get_orig_picking_ids(self): + """ + Returns the Origin Pickings from a single picking. Done in method to be + inherited in other modules, if needed. + """ + self.ensure_one() + return self.mapped("move_lines.move_orig_ids.picking_id") + + def _get_dest_picking_ids(self): + """ + Returns the Destination Pickings from a single picking. Done in method to be + inherited in other modules, if needed. + """ + self.ensure_one() + return self.mapped("move_lines.move_dest_ids.picking_id") + + @api.depends("move_lines.move_orig_ids", "move_lines.move_dest_ids") + def _compute_origin_dest_picking(self): + for picking in self: + picking.orig_picking_ids = picking._get_orig_picking_ids() + picking.dest_picking_ids = picking._get_dest_picking_ids() diff --git a/stock_picking_orig_dest_link/readme/CONTRIBUTORS.rst b/stock_picking_orig_dest_link/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..2b9e4bcfa --- /dev/null +++ b/stock_picking_orig_dest_link/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* `ForgeFlow ` + * Guillem Casassas diff --git a/stock_picking_orig_dest_link/readme/DESCRIPTION.rst b/stock_picking_orig_dest_link/readme/DESCRIPTION.rst new file mode 100644 index 000000000..734ca82c7 --- /dev/null +++ b/stock_picking_orig_dest_link/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +This module adds the link between the origin and the destination pickings through a technical field. It can latter be added in the views to show it to the user. + +For each picking in the system, it will link it to their respective Origin and Destination pickings. + +It also adds the possibility to view the Origin or Destination of a certain transfer in the list view by adding two additional columns which are hidden by default. Also, you can filter and group by the transfers. diff --git a/stock_picking_orig_dest_link/readme/ROADMAP.rst b/stock_picking_orig_dest_link/readme/ROADMAP.rst new file mode 100644 index 000000000..08e391771 --- /dev/null +++ b/stock_picking_orig_dest_link/readme/ROADMAP.rst @@ -0,0 +1 @@ +* This module is very similar to *stock_picking_show_linked* in terms of funcionalities being added. In future versions, we should consider merging the two modules into a single one. diff --git a/stock_picking_orig_dest_link/tests/__init__.py b/stock_picking_orig_dest_link/tests/__init__.py new file mode 100644 index 000000000..712c700e4 --- /dev/null +++ b/stock_picking_orig_dest_link/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_picking_orig_dest_link diff --git a/stock_picking_orig_dest_link/tests/test_stock_picking_orig_dest_link.py b/stock_picking_orig_dest_link/tests/test_stock_picking_orig_dest_link.py new file mode 100644 index 000000000..7bae1c617 --- /dev/null +++ b/stock_picking_orig_dest_link/tests/test_stock_picking_orig_dest_link.py @@ -0,0 +1,87 @@ +# Copyright 2023 ForgeFlow S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests.common import SavepointCase + + +class TestPickingOrigDestLink(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + # Models + cls.product_model = cls.env["product.product"] + cls.picking_model = cls.env["stock.picking"] + cls.partner_model = cls.env["res.partner"] + cls.move_model = cls.env["stock.move"] + + # Created records + cls.product = cls.product_model.create({"name": "Test Product"}) + cls.partner = cls.partner_model.create({"name": "Test Partner"}) + + # Data records + cls.pick_type_in = cls.env.ref("stock.picking_type_in") + cls.pick_type_out = cls.env.ref("stock.picking_type_out") + cls.stock_location = cls.env.ref("stock.stock_location_stock") + cls.customers_location = cls.env.ref("stock.stock_location_customers") + cls.suppliers_location = cls.env.ref("stock.stock_location_suppliers") + + @classmethod + def _create_in_picking(cls): + picking = cls.picking_model.create( + { + "partner_id": cls.partner.id, + "picking_type_id": cls.pick_type_in.id, + "location_id": cls.suppliers_location.id, + "location_dest_id": cls.stock_location.id, + } + ) + move_vals = { + "picking_id": picking.id, + "product_id": cls.product.id, + "location_dest_id": cls.stock_location.id, + "location_id": cls.suppliers_location.id, + "name": cls.product.name, + "product_uom_qty": 1, + "product_uom": cls.product.uom_id.id, + } + cls.move_model.create(move_vals) + return picking + + @classmethod + def _create_out_picking(cls): + picking = cls.picking_model.create( + { + "partner_id": cls.partner.id, + "picking_type_id": cls.pick_type_out.id, + "location_id": cls.stock_location.id, + "location_dest_id": cls.customers_location.id, + } + ) + move_vals = { + "picking_id": picking.id, + "product_id": cls.product.id, + "location_id": cls.stock_location.id, + "location_dest_id": cls.customers_location.id, + "name": cls.product.name, + "product_uom_qty": 1, + "product_uom": cls.product.uom_id.id, + } + cls.move_model.create(move_vals) + return picking + + @classmethod + def _link_moves_from_pickings(cls, in_picking, out_picking): + in_move_ids = in_picking.move_lines + out_move_ids = out_picking.move_lines + return in_move_ids.write({"move_dest_ids": out_move_ids}) + + def test_01_in_out_pickings(self): + # create in and out picking and links their moves + in_pick = self._create_in_picking() + out_pick = self._create_out_picking() + result = self._link_moves_from_pickings(in_pick, out_pick) + self.assertTrue(result) + # check that pickings have also been linked + self.assertEqual(in_pick.dest_picking_ids, out_pick) + self.assertEqual(out_pick.orig_picking_ids, in_pick) diff --git a/stock_picking_orig_dest_link/views/stock_picking_views.xml b/stock_picking_orig_dest_link/views/stock_picking_views.xml new file mode 100644 index 000000000..2784513c0 --- /dev/null +++ b/stock_picking_orig_dest_link/views/stock_picking_views.xml @@ -0,0 +1,37 @@ + + + + + stock.picking.tree - stock_picking_orig_dest_link + stock.picking + + + + + + + + + + stock.picking.search - stock_picking_orig_dest_link + stock.picking + + + + + + + + + +