From 4dedb2060d567f771980097e22f1e86efed99865 Mon Sep 17 00:00:00 2001 From: Emilio Pascual Date: Mon, 29 Apr 2024 13:17:29 +0200 Subject: [PATCH] [IMP] stock_move_packaging_qty: Set packaging qty reserved when move assign MT-5861 @moduon --- stock_move_packaging_qty/README.rst | 9 +- stock_move_packaging_qty/__manifest__.py | 2 +- stock_move_packaging_qty/models/stock_move.py | 69 ++++++++- .../models/stock_move_line.py | 17 +-- .../static/description/index.html | 7 +- .../tests/test_stock_move_packaging_qty.py | 144 +++++++++++++++++- .../views/stock_move_line_view.xml | 7 + 7 files changed, 224 insertions(+), 31 deletions(-) diff --git a/stock_move_packaging_qty/README.rst b/stock_move_packaging_qty/README.rst index 688d9b1a6..24f84ed3d 100644 --- a/stock_move_packaging_qty/README.rst +++ b/stock_move_packaging_qty/README.rst @@ -7,7 +7,7 @@ Stock Packaging Qty !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:f762cbab1bc1e42ef6e66f92bbd7557223f9c6faa21797ac22edb0e40fedad71 + !! source digest: sha256:07cdace5e7277b3685db9d74679a278ea321ae54914c9c32bc9be33a179b7947 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -85,10 +85,13 @@ promote its widespread use. .. |maintainer-yajo| image:: https://github.com/yajo.png?size=40px :target: https://github.com/yajo :alt: yajo +.. |maintainer-EmilioPascual| image:: https://github.com/EmilioPascual.png?size=40px + :target: https://github.com/EmilioPascual + :alt: EmilioPascual -Current `maintainer `__: +Current `maintainers `__: -|maintainer-yajo| +|maintainer-yajo| |maintainer-EmilioPascual| This module is part of the `OCA/stock-logistics-warehouse `_ project on GitHub. diff --git a/stock_move_packaging_qty/__manifest__.py b/stock_move_packaging_qty/__manifest__.py index c3a9964cf..23b0c9051 100644 --- a/stock_move_packaging_qty/__manifest__.py +++ b/stock_move_packaging_qty/__manifest__.py @@ -16,5 +16,5 @@ ], "license": "LGPL-3", "installable": True, - "maintainers": ["yajo"], + "maintainers": ["yajo", "EmilioPascual"], } diff --git a/stock_move_packaging_qty/models/stock_move.py b/stock_move_packaging_qty/models/stock_move.py index b6746f971..6c107f95b 100644 --- a/stock_move_packaging_qty/models/stock_move.py +++ b/stock_move_packaging_qty/models/stock_move.py @@ -2,7 +2,7 @@ # Copyright 2021 ForgeFlow, S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). from odoo import _, api, exceptions, fields, models -from odoo.tools import float_compare +from odoo.tools import float_compare, float_round class StockMove(models.Model): @@ -111,12 +111,7 @@ class StockMove(models.Model): if not line.product_packaging_id: line.product_packaging_qty_done = 0 continue - line.product_packaging_qty_done = ( - line.product_packaging_id._check_qty( - line.qty_done, line.product_uom_id, "DOWN" - ) - / line.product_packaging_id.qty - ) + line.product_packaging_qty_done = line.product_packaging_qty_reserved return result def _clear_quantities_to_zero(self): @@ -127,3 +122,63 @@ class StockMove(models.Model): continue line.product_packaging_qty_done = 0 return result + + def _action_assign(self, force_qty=False): + """Set the packaging qty reserved when assigning.""" + res = super()._action_assign(force_qty=force_qty) + moves_to_assign = self + move_lines_origin = self.env["stock.move.line"].read_group( + [ + ("move_id", "in", moves_to_assign.mapped("move_orig_ids").ids), + ( + "move_id.state", + "not in", + ("draft", "waiting", "confirmed", "cancel"), + ), + ("move_id.product_packaging_id", "!=", False), + ], + ["qty_done", "product_packaging_qty_done"], + ["move_id", "location_dest_id", "lot_id", "result_package_id", "owner_id"], + lazy=False, + ) + move_lines_origin_dict = { + ( + ml.get("location_dest_id")[0] if ml.get("location_dest_id") else False, + ml.get("lot_id")[0] if ml.get("lot_id") else False, + ml.get("result_package_id")[0] + if ml.get("result_package_id") + else False, + ml.get("owner_id")[0] if ml.get("owner_id") else False, + ): { + "qty_done": ml.get("qty_done"), + "product_packaging_qty_done": ml.get("product_packaging_qty_done"), + } + for ml in move_lines_origin + } + for line in moves_to_assign.move_line_ids.filtered("product_packaging_id"): + found_move_lines_origin = move_lines_origin_dict.get( + ( + line.location_id.id, + line.lot_id.id, + line.package_id.id, + line.owner_id.id, + ), + {}, + ) + if found_move_lines_origin and found_move_lines_origin.get( + "qty_done" + ) == round( + line.reserved_uom_qty, + self.env["decimal.precision"].precision_get("Product Unit of Measure"), + ): + line.product_packaging_qty_reserved = found_move_lines_origin.get( + "product_packaging_qty_done" + ) + elif not line.product_packaging_id.qty: + continue + else: + line.product_packaging_qty_reserved = float_round( + line.reserved_qty / line.product_packaging_id.qty, + precision_rounding=line.product_packaging_id.product_uom_id.rounding, + ) + return res diff --git a/stock_move_packaging_qty/models/stock_move_line.py b/stock_move_packaging_qty/models/stock_move_line.py index 273d7db66..a31dec54b 100644 --- a/stock_move_packaging_qty/models/stock_move_line.py +++ b/stock_move_packaging_qty/models/stock_move_line.py @@ -1,7 +1,6 @@ # Copyright 2024 Moduon Team S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0) -from odoo import api, fields, models -from odoo.tools import float_round +from odoo import fields, models class StockMoveLine(models.Model): @@ -13,26 +12,12 @@ class StockMoveLine(models.Model): product_packaging_qty_reserved = fields.Float( string="Reserved Pkg. Qty.", help="Product packaging quantity reserved.", - compute="_compute_product_packaging_qty_reserved", - store=True, ) product_packaging_qty_done = fields.Float( string="Done Pkg. Qty.", help="Product packaging quantity done.", ) - @api.depends("product_packaging_id", "reserved_qty") - def _compute_product_packaging_qty_reserved(self): - """Get the quantity done in product packaging.""" - self.product_packaging_qty_reserved = False - for line in self: - if not line.product_packaging_id.qty: - continue - line.product_packaging_qty_reserved = float_round( - line.reserved_qty / line.product_packaging_id.qty, - precision_rounding=line.product_packaging_id.product_uom_id.rounding, - ) - def _get_aggregated_properties(self, move_line=False, move=False): """Aggregate by product packaging too.""" result = super()._get_aggregated_properties(move_line, move) diff --git a/stock_move_packaging_qty/static/description/index.html b/stock_move_packaging_qty/static/description/index.html index d6bca9daf..65c3e397d 100644 --- a/stock_move_packaging_qty/static/description/index.html +++ b/stock_move_packaging_qty/static/description/index.html @@ -1,3 +1,4 @@ + @@ -366,7 +367,7 @@ ul.auto-toc { !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:f762cbab1bc1e42ef6e66f92bbd7557223f9c6faa21797ac22edb0e40fedad71 +!! source digest: sha256:07cdace5e7277b3685db9d74679a278ea321ae54914c9c32bc9be33a179b7947 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

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

Add packaging fields in the stock moves, their lines and their reports.

@@ -424,8 +425,8 @@ If you spotted it first, help us to smash it by providing a detailed and welcome

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.

-

Current maintainer:

-

yajo

+

Current maintainers:

+

yajo EmilioPascual

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_move_packaging_qty/tests/test_stock_move_packaging_qty.py b/stock_move_packaging_qty/tests/test_stock_move_packaging_qty.py index cc62c83c2..e1660d72b 100644 --- a/stock_move_packaging_qty/tests/test_stock_move_packaging_qty.py +++ b/stock_move_packaging_qty/tests/test_stock_move_packaging_qty.py @@ -33,6 +33,9 @@ class TestStockMovePackagingQty(TransactionCase): ) cls.customer_location = cls.env.ref("stock.stock_location_customers") cls.supplier_location = cls.env.ref("stock.stock_location_suppliers") + cls.picking_type_out = cls.env.ref("stock.picking_type_out") + cls.pack_location = cls.env.ref("stock.location_pack_zone") + cls.stock_location = cls.env.ref("stock.stock_location_stock") def test_product_packaging_qty(self): move = self.env["stock.move"].create( @@ -57,7 +60,7 @@ class TestStockMovePackagingQty(TransactionCase): def test_product_uom_qty_change(self): picking_f = Form(self.env["stock.picking"]) picking_f.partner_id = self.partner - picking_f.picking_type_id = self.env.ref("stock.picking_type_out") + picking_f.picking_type_id = self.picking_type_out with picking_f.move_ids_without_package.new() as move_f: move_f.product_id = self.product self.assertEqual(move_f.product_uom_qty, 1) @@ -83,3 +86,142 @@ class TestStockMovePackagingQty(TransactionCase): ], ) picking.button_validate() + + def test_product_packaging_qty_reserved(self): + """Test that the product packaging quantity reserved is correctly set.""" + product_a = self.env["product.product"].create( + {"name": "Product A", "type": "product"} + ) + packaging_product_a = self.env["product.packaging"].create( + {"name": "Test packaging", "product_id": product_a.id, "qty": 5.0} + ) + self.pack_location.active = True + MoveObj = self.env["stock.move"] + picking_client = self.env["stock.picking"].create( + { + "location_id": self.pack_location.id, + "location_dest_id": self.customer_location.id, + "picking_type_id": self.picking_type_out.id, + } + ) + dest = MoveObj.create( + { + "name": product_a.name, + "product_id": product_a.id, + "product_uom_qty": 10, + "product_uom": product_a.uom_id.id, + "picking_id": picking_client.id, + "location_id": self.pack_location.id, + "location_dest_id": self.customer_location.id, + "state": "waiting", + "procure_method": "make_to_order", + "product_packaging_id": packaging_product_a.id, + } + ) + picking_pick = self.env["stock.picking"].create( + { + "location_id": self.stock_location.id, + "location_dest_id": self.pack_location.id, + "picking_type_id": self.picking_type_out.id, + } + ) + MoveObj.create( + { + "name": product_a.name, + "product_id": product_a.id, + "product_uom_qty": 10, + "product_uom": product_a.uom_id.id, + "picking_id": picking_pick.id, + "location_id": self.stock_location.id, + "location_dest_id": self.pack_location.id, + "move_dest_ids": [(4, dest.id)], + "state": "confirmed", + "product_packaging_id": packaging_product_a.id, + } + ) + self.env["stock.quant"]._update_available_quantity( + product_a, self.stock_location, 10 + ) + picking_pick.action_assign() + self.assertRecordValues( + picking_pick.move_ids_without_package, + [ + { + "product_id": product_a.id, + "product_packaging_id": packaging_product_a.id, + "product_packaging_qty": 2, + "product_uom_qty": 10, + "quantity_done": 0, + "product_packaging_qty_done": 0, + } + ], + ) + self.assertRecordValues( + picking_pick.move_line_ids_without_package, + [ + { + "product_id": product_a.id, + "product_packaging_id": packaging_product_a.id, + "reserved_uom_qty": 10, + "product_packaging_qty_reserved": 2, + "qty_done": 0, + "product_packaging_qty_done": 0, + } + ], + ) + picking_pick.action_set_quantities_to_reservation() + self.assertRecordValues( + picking_pick.move_ids_without_package, + [ + { + "product_id": product_a.id, + "product_packaging_id": packaging_product_a.id, + "product_packaging_qty": 2, + "product_uom_qty": 10, + "quantity_done": 10, + "product_packaging_qty_done": 2, + } + ], + ) + picking_pick._action_done() + picking_client.action_assign() + self.assertRecordValues( + picking_client.move_ids_without_package, + [ + { + "product_id": product_a.id, + "product_packaging_id": packaging_product_a.id, + "product_packaging_qty": 2, + "product_uom_qty": 10, + "quantity_done": 0, + "product_packaging_qty_done": 0, + } + ], + ) + self.assertRecordValues( + picking_client.move_line_ids_without_package, + [ + { + "product_id": product_a.id, + "product_packaging_id": packaging_product_a.id, + "reserved_uom_qty": 10, + "product_packaging_qty_reserved": 2, + "qty_done": 0, + "product_packaging_qty_done": 0, + } + ], + ) + picking_pick.action_set_quantities_to_reservation() + self.assertRecordValues( + picking_pick.move_ids_without_package, + [ + { + "product_id": product_a.id, + "product_packaging_id": packaging_product_a.id, + "product_packaging_qty": 2, + "product_uom_qty": 10, + "quantity_done": 10, + "product_packaging_qty_done": 2, + } + ], + ) diff --git a/stock_move_packaging_qty/views/stock_move_line_view.xml b/stock_move_packaging_qty/views/stock_move_line_view.xml index 195ba777e..b8a967ce4 100644 --- a/stock_move_packaging_qty/views/stock_move_line_view.xml +++ b/stock_move_packaging_qty/views/stock_move_line_view.xml @@ -7,6 +7,13 @@ stock.move.line + + +