From c4fefff62246e65556ac22a21553b5f576ee2778 Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Thu, 13 Apr 2023 20:41:35 +0200 Subject: [PATCH 1/2] prod_lot_seq: Fix sequence incrementation opening detailed operations When opening the detailed operations view of a stock move, Odoo is calling stock.production.lot._get_next_serial to set stock.move.next_serial field anytime the product is tracked by serial and the move is assigned. If we use this module with product or global policy, the respective sequence will therefore be called and incremented anytime this view is open, even if the picking is not creating lots (e.g. delivery orders or internal transfers) To avoid incrementing the sequence unnecessarily, we only allow to get the next sequence number the first time this view is opened and if the move has to create new serial numbers. Otherwise, we force the value to be set to stock.move.next_serial field to an empty string if no serial has to be created through this move, or to the next_serial value assigned on the first opening of the view. --- product_lot_sequence/README.rst | 17 ++++++- product_lot_sequence/models/__init__.py | 1 + product_lot_sequence/models/stock_lot.py | 2 + product_lot_sequence/models/stock_move.py | 23 +++++++++ product_lot_sequence/readme/ROADMAP.rst | 11 +++++ .../static/description/index.html | 37 +++++++++----- .../tests/test_product_lot_sequence.py | 49 +++++++++++++++++++ 7 files changed, 128 insertions(+), 12 deletions(-) create mode 100644 product_lot_sequence/models/stock_move.py create mode 100644 product_lot_sequence/readme/ROADMAP.rst diff --git a/product_lot_sequence/README.rst b/product_lot_sequence/README.rst index 32a2a808868..180b71594ea 100644 --- a/product_lot_sequence/README.rst +++ b/product_lot_sequence/README.rst @@ -7,7 +7,7 @@ Product Lot Sequence !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:dfe9a2666cd1599203c70fd159399022104a8f2df4808574a961f49e93399cf1 + !! source digest: sha256:c497d170778ffa1220e7cd95c340001c2d7caad3c29559a226d0bd3bc9d5d6fb !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -73,6 +73,21 @@ To use this module: * Create new Lot/Serial number * Select the product and the next number of the product sequence will be automatically proposed +Known issues / Roadmap +====================== + +* There is an issue with the use of ir.sequence with the newer version of Odoo. + +Mostly, when opening the detailed operations of an assigned picking for a product +tracked by serial numbers, Odoo systematically calls `_get_next_serial` even +if there is not any serial number to generate. +Moreover, the widget allowing to generate the serial numbers will not call +the sequence but only increment the number according to the next serial, +potentially leading to a sequence that is not in sync anymore with the created +serial numbers. + +cf https://github.com/OCA/product-attribute/issues/1326 + Bug Tracker =========== diff --git a/product_lot_sequence/models/__init__.py b/product_lot_sequence/models/__init__.py index 1c7180fd3ea..3dceccb802b 100644 --- a/product_lot_sequence/models/__init__.py +++ b/product_lot_sequence/models/__init__.py @@ -2,3 +2,4 @@ from . import product from . import res_config_settings from . import stock_lot +from . import stock_move diff --git a/product_lot_sequence/models/stock_lot.py b/product_lot_sequence/models/stock_lot.py index 38be74dc217..105ff98773f 100644 --- a/product_lot_sequence/models/stock_lot.py +++ b/product_lot_sequence/models/stock_lot.py @@ -56,6 +56,8 @@ def create(self, vals_list): @api.model def _get_next_serial(self, company, product): + if "force_next_serial" in self.env.context: + return self.env.context.get("force_next_serial") seq_policy = self._get_sequence_policy() if seq_policy == "product": seq = product.product_tmpl_id.lot_sequence_id diff --git a/product_lot_sequence/models/stock_move.py b/product_lot_sequence/models/stock_move.py new file mode 100644 index 00000000000..c95ef7e1dc6 --- /dev/null +++ b/product_lot_sequence/models/stock_move.py @@ -0,0 +1,23 @@ +# Copyright 2023 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from odoo import models + + +class StockMove(models.Model): + _inherit = "stock.move" + + def action_show_details(self): + """Avoid calling and incrementing the sequence if not needed or already done""" + seq_policy = self.env["stock.production.lot"]._get_sequence_policy() + if seq_policy in ("product", "global"): + # If move is not supposed to assign serial pass empty string for next serial + if not self.display_assign_serial: + return super( + StockMove, self.with_context(force_next_serial="") + ).action_show_details() + # If the sequence was already called once, avoid calling it another time + elif self.next_serial: + return super( + StockMove, self.with_context(force_next_serial=self.next_serial) + ).action_show_details() + return super().action_show_details() diff --git a/product_lot_sequence/readme/ROADMAP.rst b/product_lot_sequence/readme/ROADMAP.rst new file mode 100644 index 00000000000..f13e32e249c --- /dev/null +++ b/product_lot_sequence/readme/ROADMAP.rst @@ -0,0 +1,11 @@ +* There is an issue with the use of ir.sequence with the newer version of Odoo. + +Mostly, when opening the detailed operations of an assigned picking for a product +tracked by serial numbers, Odoo systematically calls `_get_next_serial` even +if there is not any serial number to generate. +Moreover, the widget allowing to generate the serial numbers will not call +the sequence but only increment the number according to the next serial, +potentially leading to a sequence that is not in sync anymore with the created +serial numbers. + +cf https://github.com/OCA/product-attribute/issues/1326 diff --git a/product_lot_sequence/static/description/index.html b/product_lot_sequence/static/description/index.html index 9768894dafb..7fe286b8f35 100644 --- a/product_lot_sequence/static/description/index.html +++ b/product_lot_sequence/static/description/index.html @@ -367,7 +367,7 @@

Product Lot Sequence

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:dfe9a2666cd1599203c70fd159399022104a8f2df4808574a961f49e93399cf1 +!! source digest: sha256:c497d170778ffa1220e7cd95c340001c2d7caad3c29559a226d0bd3bc9d5d6fb !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

Adds ability to define a lot sequence from the product which will be proposed upon creating new lots.

@@ -380,11 +380,12 @@

Product Lot Sequence

  • Usage
  • -
  • Bug Tracker
  • -
  • Credits @@ -424,8 +425,22 @@

    Usage

  • Select the product and the next number of the product sequence will be automatically proposed
  • +
    +

    Known issues / Roadmap

    + +

    Mostly, when opening the detailed operations of an assigned picking for a product +tracked by serial numbers, Odoo systematically calls _get_next_serial even +if there is not any serial number to generate. +Moreover, the widget allowing to generate the serial numbers will not call +the sequence but only increment the number according to the next serial, +potentially leading to a sequence that is not in sync anymore with the created +serial numbers.

    +

    cf https://github.com/OCA/product-attribute/issues/1326

    +
    -

    Bug Tracker

    +

    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 @@ -433,15 +448,15 @@

    Bug Tracker

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

    -

    Credits

    +

    Credits

    -

    Authors

    +

    Authors

    • ForgeFlow S.L.
    -

    Contributors

    +

    Contributors

    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association

    OCA, or the Odoo Community Association, is a nonprofit organization whose diff --git a/product_lot_sequence/tests/test_product_lot_sequence.py b/product_lot_sequence/tests/test_product_lot_sequence.py index 97902bb711a..f90264f6cee 100644 --- a/product_lot_sequence/tests/test_product_lot_sequence.py +++ b/product_lot_sequence/tests/test_product_lot_sequence.py @@ -9,6 +9,22 @@ def setUp(self): super(TestProductLotSequence, self).setUp() self.product_product = self.env["product.product"] self.stock_production_lot = self.env["stock.lot"] + self.receipt_type = self.env.ref("stock.picking_type_in") + self.delivery_type = self.env.ref("stock.picking_type_out") + + def _create_picking(self, picking_type, move_vals_list): + picking_form = Form(self.env["stock.picking"]) + picking_form.picking_type_id = picking_type + for move_vals in move_vals_list: + with picking_form.move_ids_without_package.new() as move_form: + move_form.product_id = move_vals.get("product_id") + move_form.product_uom_qty = move_vals.get("product_uom_qty", 1.0) + move_form.product_uom = move_vals.get( + "product_uom", self.env.ref("uom.product_uom_unit") + ) + picking = picking_form.save() + picking.action_confirm() + return picking def test_product_sequence(self): self.assertEqual(self.stock_production_lot._get_sequence_policy(), "product") @@ -86,3 +102,36 @@ def test_lot_onchange_product_id_global(self): lot_form.product_id = product lot = lot_form.save() self.assertEqual(lot.name, next_sequence_number) + + def test_open_detailed_operations(self): + self.env["ir.config_parameter"].set_param( + "product_lot_sequence.policy", "global" + ) + seq = self.env["ir.sequence"].search([("code", "=", "stock.lot.serial")]) + first_next_sequence_number = seq.get_next_char(seq.number_next_actual) + product = self.product_product.create( + {"name": "Test global", "tracking": "serial"} + ) + delivery_picking = self._create_picking( + self.delivery_type, [{"product_id": product}] + ) + delivery_move = delivery_picking.move_lines + self.assertFalse(delivery_move.next_serial) + delivery_move.action_show_details() + self.assertFalse(delivery_move.next_serial) + self.assertEqual( + seq.get_next_char(seq.number_next_actual), first_next_sequence_number + ) + receipt_picking = self._create_picking( + self.receipt_type, [{"product_id": product}] + ) + receipt_move = receipt_picking.move_lines + self.assertFalse(receipt_move.next_serial) + receipt_move.action_show_details() + self.assertEqual(receipt_move.next_serial, first_next_sequence_number) + new_next_sequence_number = seq.get_next_char(seq.number_next_actual) + self.assertNotEqual(new_next_sequence_number, first_next_sequence_number) + receipt_move.action_show_details() + self.assertEqual( + new_next_sequence_number, seq.get_next_char(seq.number_next_actual) + ) From 8d070b306aefdb9198e8528cb550cf6512c6db48 Mon Sep 17 00:00:00 2001 From: Vincent Van Rossem Date: Wed, 20 Mar 2024 16:00:26 +0100 Subject: [PATCH 2/2] product_lot_sequence: port fix from 15.0 to 16.0 --- product_lot_sequence/README.rst | 9 +++++++-- product_lot_sequence/models/stock_move.py | 12 ++++-------- product_lot_sequence/readme/CONTRIBUTORS.rst | 7 ++++++- product_lot_sequence/static/description/index.html | 6 +++++- .../tests/test_product_lot_sequence.py | 7 +++++-- 5 files changed, 27 insertions(+), 14 deletions(-) diff --git a/product_lot_sequence/README.rst b/product_lot_sequence/README.rst index 180b71594ea..4fe5c2302a6 100644 --- a/product_lot_sequence/README.rst +++ b/product_lot_sequence/README.rst @@ -7,7 +7,7 @@ Product Lot Sequence !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:c497d170778ffa1220e7cd95c340001c2d7caad3c29559a226d0bd3bc9d5d6fb + !! source digest: sha256:568bfc6b73360be36291cdcf8aa0d184a57b2701e2ff2798311977a8be099b31 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -111,7 +111,12 @@ Contributors * Adria Gil Sorribes * Domantas Girdžiūnas -* Akim Juillerat + +* `Camptocamp `__: + + * Akim Juillerat + * Vincent Van Rossem + * `Quartile `__: * Yoshi Tashiro diff --git a/product_lot_sequence/models/stock_move.py b/product_lot_sequence/models/stock_move.py index c95ef7e1dc6..603c782803a 100644 --- a/product_lot_sequence/models/stock_move.py +++ b/product_lot_sequence/models/stock_move.py @@ -8,16 +8,12 @@ class StockMove(models.Model): def action_show_details(self): """Avoid calling and incrementing the sequence if not needed or already done""" - seq_policy = self.env["stock.production.lot"]._get_sequence_policy() + seq_policy = self.env["stock.lot"]._get_sequence_policy() if seq_policy in ("product", "global"): # If move is not supposed to assign serial pass empty string for next serial if not self.display_assign_serial: - return super( - StockMove, self.with_context(force_next_serial="") - ).action_show_details() + self = self.with_context(force_next_serial="") # If the sequence was already called once, avoid calling it another time elif self.next_serial: - return super( - StockMove, self.with_context(force_next_serial=self.next_serial) - ).action_show_details() - return super().action_show_details() + self = self.with_context(force_next_serial=self.next_serial) + return super(StockMove, self).action_show_details() diff --git a/product_lot_sequence/readme/CONTRIBUTORS.rst b/product_lot_sequence/readme/CONTRIBUTORS.rst index 8248c18a690..e6fd36a2adc 100644 --- a/product_lot_sequence/readme/CONTRIBUTORS.rst +++ b/product_lot_sequence/readme/CONTRIBUTORS.rst @@ -1,6 +1,11 @@ * Adria Gil Sorribes * Domantas Girdžiūnas -* Akim Juillerat + +* `Camptocamp `__: + + * Akim Juillerat + * Vincent Van Rossem + * `Quartile `__: * Yoshi Tashiro diff --git a/product_lot_sequence/static/description/index.html b/product_lot_sequence/static/description/index.html index 7fe286b8f35..73b8f6dc2d5 100644 --- a/product_lot_sequence/static/description/index.html +++ b/product_lot_sequence/static/description/index.html @@ -367,7 +367,7 @@

    Product Lot Sequence

    !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:c497d170778ffa1220e7cd95c340001c2d7caad3c29559a226d0bd3bc9d5d6fb +!! source digest: sha256:568bfc6b73360be36291cdcf8aa0d184a57b2701e2ff2798311977a8be099b31 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

    Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    Adds ability to define a lot sequence from the product which will be proposed upon creating new lots.

    @@ -460,7 +460,11 @@

    Contributors

    • Adria Gil Sorribes <adria.gil@forgeflow.com>
    • Domantas Girdžiūnas <domantas@vialaurea.lt>
    • +
    • Camptocamp: +
    • Quartile:
      • Yoshi Tashiro
      diff --git a/product_lot_sequence/tests/test_product_lot_sequence.py b/product_lot_sequence/tests/test_product_lot_sequence.py index f90264f6cee..fe1db7399f4 100644 --- a/product_lot_sequence/tests/test_product_lot_sequence.py +++ b/product_lot_sequence/tests/test_product_lot_sequence.py @@ -104,6 +104,9 @@ def test_lot_onchange_product_id_global(self): self.assertEqual(lot.name, next_sequence_number) def test_open_detailed_operations(self): + # Required for `product_uom` to be visible in the view + self.env.user.groups_id += self.env.ref("uom.group_uom") + self.env["ir.config_parameter"].set_param( "product_lot_sequence.policy", "global" ) @@ -115,7 +118,7 @@ def test_open_detailed_operations(self): delivery_picking = self._create_picking( self.delivery_type, [{"product_id": product}] ) - delivery_move = delivery_picking.move_lines + delivery_move = delivery_picking.move_ids self.assertFalse(delivery_move.next_serial) delivery_move.action_show_details() self.assertFalse(delivery_move.next_serial) @@ -125,7 +128,7 @@ def test_open_detailed_operations(self): receipt_picking = self._create_picking( self.receipt_type, [{"product_id": product}] ) - receipt_move = receipt_picking.move_lines + receipt_move = receipt_picking.move_ids self.assertFalse(receipt_move.next_serial) receipt_move.action_show_details() self.assertEqual(receipt_move.next_serial, first_next_sequence_number)