From 7635265b09c2aa7e495414a9931ad828fe61a76e Mon Sep 17 00:00:00 2001 From: Joan Sisquella Date: Wed, 18 Oct 2023 11:57:39 +0200 Subject: [PATCH 01/13] [ADD] sale_order_line_remove: allows the removal of sale order lines --- sale_order_line_remove/__init__.py | 2 + sale_order_line_remove/__manifest__.py | 16 +++ sale_order_line_remove/models/__init__.py | 1 + sale_order_line_remove/models/sale_order.py | 42 ++++++ .../readme/CONTRIBUTORS.rst | 1 + sale_order_line_remove/readme/DESCRIPTION.rst | 4 + sale_order_line_remove/readme/USAGE.rst | 4 + sale_order_line_remove/tests/__init__.py | 1 + .../tests/test_sale_order_line.py | 123 ++++++++++++++++++ 9 files changed, 194 insertions(+) create mode 100644 sale_order_line_remove/__init__.py create mode 100644 sale_order_line_remove/__manifest__.py create mode 100644 sale_order_line_remove/models/__init__.py create mode 100644 sale_order_line_remove/models/sale_order.py create mode 100644 sale_order_line_remove/readme/CONTRIBUTORS.rst create mode 100644 sale_order_line_remove/readme/DESCRIPTION.rst create mode 100644 sale_order_line_remove/readme/USAGE.rst create mode 100644 sale_order_line_remove/tests/__init__.py create mode 100644 sale_order_line_remove/tests/test_sale_order_line.py diff --git a/sale_order_line_remove/__init__.py b/sale_order_line_remove/__init__.py new file mode 100644 index 00000000000..0ee8b5073e2 --- /dev/null +++ b/sale_order_line_remove/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import tests diff --git a/sale_order_line_remove/__manifest__.py b/sale_order_line_remove/__manifest__.py new file mode 100644 index 00000000000..60d43dcb2f1 --- /dev/null +++ b/sale_order_line_remove/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2023 ForgeFlow, S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Sale Order Line Remove", + "version": "13.0.1.0.0", + "category": "Sales", + "summary": "Allows removal of sale order lines from confirmed " + "orders if not invoiced or received", + "author": "ForgeFlow, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/sale-workflow", + "license": "AGPL-3", + "depends": ["sale_stock"], + "data": [], + "installable": True, + "application": False, +} diff --git a/sale_order_line_remove/models/__init__.py b/sale_order_line_remove/models/__init__.py new file mode 100644 index 00000000000..6aacb753131 --- /dev/null +++ b/sale_order_line_remove/models/__init__.py @@ -0,0 +1 @@ +from . import sale_order diff --git a/sale_order_line_remove/models/sale_order.py b/sale_order_line_remove/models/sale_order.py new file mode 100644 index 00000000000..0b9150c7953 --- /dev/null +++ b/sale_order_line_remove/models/sale_order.py @@ -0,0 +1,42 @@ +# Copyright 2023 ForgeFlow, S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import _, models +from odoo.exceptions import UserError + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + def _check_line_unlink(self): + non_removable_lines = super(SaleOrderLine, self)._check_line_unlink() + removable_lines = self.filtered( + lambda line: line.state in ("sale", "done") + and not line.invoice_lines + and not line.move_ids.filtered(lambda move: move.state == "done") + ) + invoiced_lines = self.filtered( + lambda line: line.state in ("sale", "done") and line.invoice_lines + ) + if invoiced_lines: + raise UserError( + _("You can not remove an order line that has been invoiced") + ) + delivered_lines = self.filtered( + lambda line: line.state in ("sale", "done") + and line.move_ids.filtered(lambda move: move.state == "done") + ) + if delivered_lines: + raise UserError( + _("You can not remove an order line that has been delivered") + ) + return non_removable_lines - removable_lines + + def unlink(self): + non_removable_lines = self._check_line_unlink() + for line in self - non_removable_lines: + line.move_ids.filtered( + lambda move: move.state not in ("done", "cancel") + )._action_cancel() + line.move_ids.filtered(lambda move: move.state != "done").unlink() + return super(SaleOrderLine, self).unlink() diff --git a/sale_order_line_remove/readme/CONTRIBUTORS.rst b/sale_order_line_remove/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..1023a5dd6b1 --- /dev/null +++ b/sale_order_line_remove/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Joan Sisquella diff --git a/sale_order_line_remove/readme/DESCRIPTION.rst b/sale_order_line_remove/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..a780df2764b --- /dev/null +++ b/sale_order_line_remove/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +This module allows the removal of sale order lines even after the order has been confirmed, under certain conditions. Specifically, a sale order line can be removed if: + +- It has not been invoiced. +- It has not been delivered. diff --git a/sale_order_line_remove/readme/USAGE.rst b/sale_order_line_remove/readme/USAGE.rst new file mode 100644 index 00000000000..9690625f535 --- /dev/null +++ b/sale_order_line_remove/readme/USAGE.rst @@ -0,0 +1,4 @@ +Once the module is installed: + +1. Go to a sale order. +2. You can now delete a sale order line if it hasn't been invoiced or delivered. diff --git a/sale_order_line_remove/tests/__init__.py b/sale_order_line_remove/tests/__init__.py new file mode 100644 index 00000000000..2283b3b0b2f --- /dev/null +++ b/sale_order_line_remove/tests/__init__.py @@ -0,0 +1 @@ +from . import test_sale_order_line diff --git a/sale_order_line_remove/tests/test_sale_order_line.py b/sale_order_line_remove/tests/test_sale_order_line.py new file mode 100644 index 00000000000..f41fa33325e --- /dev/null +++ b/sale_order_line_remove/tests/test_sale_order_line.py @@ -0,0 +1,123 @@ +# Copyright 2023 ForgeFlow, S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo.tests import TransactionCase + + +class TestSaleOrderLine(TransactionCase): + def setUp(self): + super(TestSaleOrderLine, self).setUp() + self.SaleOrder = self.env["sale.order"] + self.SaleOrderLine = self.env["sale.order.line"] + self.partner = self.env.ref("base.res_partner_2") + self.product = self.env.ref("product.product_product_4") + self.uom = self.env.ref("uom.product_uom_unit") + + def test_check_line_unlink(self): + sale_order = self.SaleOrder.create({"partner_id": self.partner.id}) + sale_order.action_confirm() + sale_order_line = self.SaleOrderLine.create( + { + "order_id": sale_order.id, + "product_id": self.product.id, + "product_uom_qty": 1, + "product_uom": self.uom.id, + } + ) + non_removable_lines = sale_order_line._check_line_unlink() + self.assertFalse(non_removable_lines, "Line should not be non-removable") + + def test_unlink(self): + sale_order = self.SaleOrder.create({"partner_id": self.partner.id}) + sale_order.action_confirm() + sale_order_line = self.SaleOrderLine.create( + { + "order_id": sale_order.id, + "product_id": self.product.id, + "product_uom_qty": 1, + "product_uom": self.uom.id, + } + ) + sale_order_line.unlink() + self.assertFalse(sale_order_line.exists(), "Sale order line was not deleted") + + def test_check_line_not_unlinkable(self): + sale_order = self.SaleOrder.create({"partner_id": self.partner.id}) + sale_order.action_confirm() + sale_order_line = self.SaleOrderLine.create( + { + "order_id": sale_order.id, + "product_id": self.product.id, + "product_uom_qty": 1, + "product_uom": self.uom.id, + } + ) + picking = sale_order.picking_ids[0] + picking.action_confirm() + picking.action_assign() + for move in picking.move_ids_without_package: + move.quantity_done = move.product_uom_qty + picking.button_validate() + with self.assertRaises(Exception): + sale_order_line._check_line_unlink() + + def test_not_unlinkable_after_picking(self): + sale_order = self.SaleOrder.create({"partner_id": self.partner.id}) + sale_order.action_confirm() + sale_order_line = self.SaleOrderLine.create( + { + "order_id": sale_order.id, + "product_id": self.product.id, + "product_uom_qty": 1, + "product_uom": self.uom.id, + } + ) + picking = sale_order.picking_ids[0] + picking.action_confirm() + picking.action_assign() + for move in picking.move_ids_without_package: + move.quantity_done = move.product_uom_qty + picking.button_validate() + with self.assertRaises(Exception): + sale_order_line.unlink() + + def test_check_line_unlink_delivered(self): + sale_order = self.SaleOrder.create({"partner_id": self.partner.id}) + sale_order.action_confirm() + sale_order_line = self.SaleOrderLine.create( + { + "order_id": sale_order.id, + "product_id": self.product.id, + "product_uom_qty": 1, + "product_uom": self.uom.id, + } + ) + picking = sale_order.picking_ids[0] + picking.action_confirm() + picking.action_assign() + for move in picking.move_ids_without_package: + move.quantity_done = move.product_uom_qty + picking.button_validate() + with self.assertRaises(Exception): + sale_order_line._check_line_unlink() + + def test_check_line_unlink_invoiced(self): + sale_order = self.SaleOrder.create({"partner_id": self.partner.id}) + sale_order.action_confirm() + sale_order_line = self.SaleOrderLine.create( + { + "order_id": sale_order.id, + "product_id": self.product.id, + "product_uom_qty": 1, + "product_uom": self.uom.id, + } + ) + picking = sale_order.picking_ids[0] + picking.action_confirm() + picking.action_assign() + for move in picking.move_ids_without_package: + move.quantity_done = move.product_uom_qty + picking.button_validate() + sale_order._create_invoices() + with self.assertRaises(Exception): + sale_order_line._check_line_unlink() From c84c52d76d61add703e53ff3a3dc6c5958d7bd59 Mon Sep 17 00:00:00 2001 From: Joan Sisquella Date: Mon, 23 Oct 2023 10:17:12 +0200 Subject: [PATCH 02/13] [ADD] sale_order_line_remove: cancel related picking if all the lines are cancelled --- sale_order_line_remove/models/sale_order.py | 8 +++-- .../tests/test_sale_order_line.py | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/sale_order_line_remove/models/sale_order.py b/sale_order_line_remove/models/sale_order.py index 0b9150c7953..fb64c13f2ef 100644 --- a/sale_order_line_remove/models/sale_order.py +++ b/sale_order_line_remove/models/sale_order.py @@ -15,14 +15,14 @@ def _check_line_unlink(self): and not line.invoice_lines and not line.move_ids.filtered(lambda move: move.state == "done") ) - invoiced_lines = self.filtered( + invoiced_lines = self.sudo().filtered( lambda line: line.state in ("sale", "done") and line.invoice_lines ) if invoiced_lines: raise UserError( _("You can not remove an order line that has been invoiced") ) - delivered_lines = self.filtered( + delivered_lines = self.sudo().filtered( lambda line: line.state in ("sale", "done") and line.move_ids.filtered(lambda move: move.state == "done") ) @@ -35,8 +35,12 @@ def _check_line_unlink(self): def unlink(self): non_removable_lines = self._check_line_unlink() for line in self - non_removable_lines: + related_pickings = line.move_ids.mapped("picking_id") line.move_ids.filtered( lambda move: move.state not in ("done", "cancel") )._action_cancel() line.move_ids.filtered(lambda move: move.state != "done").unlink() + for picking in related_pickings: + if not picking.move_ids_without_package: + picking.unlink() return super(SaleOrderLine, self).unlink() diff --git a/sale_order_line_remove/tests/test_sale_order_line.py b/sale_order_line_remove/tests/test_sale_order_line.py index f41fa33325e..beaf0d1fb97 100644 --- a/sale_order_line_remove/tests/test_sale_order_line.py +++ b/sale_order_line_remove/tests/test_sale_order_line.py @@ -121,3 +121,33 @@ def test_check_line_unlink_invoiced(self): sale_order._create_invoices() with self.assertRaises(Exception): sale_order_line._check_line_unlink() + + def test_unlink_empty_picking(self): + sale_order = self.SaleOrder.create({"partner_id": self.partner.id}) + sale_order.action_confirm() + sale_order_line1 = self.SaleOrderLine.create( + { + "order_id": sale_order.id, + "product_id": self.product.id, + "product_uom_qty": 1, + "product_uom": self.uom.id, + } + ) + sale_order_line2 = self.SaleOrderLine.create( + { + "order_id": sale_order.id, + "product_id": self.product.id, + "product_uom_qty": 1, + "product_uom": self.uom.id, + } + ) + picking = sale_order.picking_ids[0] + picking.action_confirm() + picking.action_assign() + sale_order_line1.unlink() + self.assertTrue(picking.exists(), "Picking was deleted") + self.assertNotEqual( + picking.state, "cancel", "Picking should not be cancelled yet" + ) + sale_order_line2.unlink() + self.assertFalse(picking.exists(), "Picking was not deleted") From fe5bdf236f1d1e2b50425566fabad64d7a98d5b5 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Fri, 27 Oct 2023 09:49:33 +0000 Subject: [PATCH 03/13] [UPD] Update sale_order_line_remove.pot --- .../i18n/sale_order_line_remove.pot | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 sale_order_line_remove/i18n/sale_order_line_remove.pot diff --git a/sale_order_line_remove/i18n/sale_order_line_remove.pot b/sale_order_line_remove/i18n/sale_order_line_remove.pot new file mode 100644 index 00000000000..cb55d497000 --- /dev/null +++ b/sale_order_line_remove/i18n/sale_order_line_remove.pot @@ -0,0 +1,31 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_line_remove +# +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: sale_order_line_remove +#: model:ir.model,name:sale_order_line_remove.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_order_line_remove +#: code:addons/sale_order_line_remove/models/sale_order.py:0 +#, python-format +msgid "You can not remove an order line that has been delivered" +msgstr "" + +#. module: sale_order_line_remove +#: code:addons/sale_order_line_remove/models/sale_order.py:0 +#, python-format +msgid "You can not remove an order line that has been invoiced" +msgstr "" From 1b378be604b8e559e193ed0f3b73bd7d911a299c Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Fri, 27 Oct 2023 10:03:17 +0000 Subject: [PATCH 04/13] [BOT] post-merge updates --- sale_order_line_remove/README.rst | 87 ++++ .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 434 ++++++++++++++++++ 3 files changed, 521 insertions(+) create mode 100644 sale_order_line_remove/README.rst create mode 100644 sale_order_line_remove/static/description/icon.png create mode 100644 sale_order_line_remove/static/description/index.html diff --git a/sale_order_line_remove/README.rst b/sale_order_line_remove/README.rst new file mode 100644 index 00000000000..6e91c375642 --- /dev/null +++ b/sale_order_line_remove/README.rst @@ -0,0 +1,87 @@ +====================== +Sale Order Line Remove +====================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:2017e8c089ea3193365d2780d28f22d8fe129ffe9f0796aef565f75343968bdd + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fsale--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/sale-workflow/tree/13.0/sale_order_line_remove + :alt: OCA/sale-workflow +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/sale-workflow-13-0/sale-workflow-13-0-sale_order_line_remove + :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/sale-workflow&target_branch=13.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows the removal of sale order lines even after the order has been confirmed, under certain conditions. Specifically, a sale order line can be removed if: + +- It has not been invoiced. +- It has not been delivered. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Once the module is installed: + +1. Go to a sale order. +2. You can now delete a sale order line if it hasn't been invoiced or delivered. + +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 +~~~~~~~ + +* ForgeFlow + +Contributors +~~~~~~~~~~~~ + +* Joan Sisquella + +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/sale-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_order_line_remove/static/description/icon.png b/sale_order_line_remove/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/sale_order_line_remove/static/description/index.html b/sale_order_line_remove/static/description/index.html new file mode 100644 index 00000000000..72a81b07a7f --- /dev/null +++ b/sale_order_line_remove/static/description/index.html @@ -0,0 +1,434 @@ + + + + + + +Sale Order Line Remove + + + +
+

Sale Order Line Remove

+ + +

Beta License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

+

This module allows the removal of sale order lines even after the order has been confirmed, under certain conditions. Specifically, a sale order line can be removed if:

+
    +
  • It has not been invoiced.
  • +
  • It has not been delivered.
  • +
+

Table of contents

+ +
+

Usage

+

Once the module is installed:

+
    +
  1. Go to a sale order.
  2. +
  3. You can now delete a sale order line if it hasn’t been invoiced or delivered.
  4. +
+
+
+

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

+
    +
  • ForgeFlow
  • +
+
+
+

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/sale-workflow project on GitHub.

+

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

+
+
+
+ + From 2fd46ed55f2d27f9c4af0d8fc32b415927bfef75 Mon Sep 17 00:00:00 2001 From: Joan Sisquella Date: Wed, 8 Nov 2023 12:13:28 +0100 Subject: [PATCH 05/13] [MIG] sale_order_line_remove: Migration to 15.0 --- sale_order_line_remove/README.rst | 12 ++++++------ sale_order_line_remove/__init__.py | 1 - sale_order_line_remove/__manifest__.py | 2 +- sale_order_line_remove/static/description/index.html | 8 ++++---- sale_order_line_remove/tests/test_sale_order_line.py | 9 +++++---- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/sale_order_line_remove/README.rst b/sale_order_line_remove/README.rst index 6e91c375642..36dd7656ec6 100644 --- a/sale_order_line_remove/README.rst +++ b/sale_order_line_remove/README.rst @@ -7,7 +7,7 @@ Sale Order Line Remove !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:2017e8c089ea3193365d2780d28f22d8fe129ffe9f0796aef565f75343968bdd + !! source digest: sha256:19987b79fe99d4ff465bda1d9b1f07c5570e70b5347127ddb2dcc5849efb6bc4 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -17,13 +17,13 @@ Sale Order Line Remove :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github - :target: https://github.com/OCA/sale-workflow/tree/13.0/sale_order_line_remove + :target: https://github.com/OCA/sale-workflow/tree/15.0/sale_order_line_remove :alt: OCA/sale-workflow .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/sale-workflow-13-0/sale-workflow-13-0-sale_order_line_remove + :target: https://translation.odoo-community.org/projects/sale-workflow-15-0/sale-workflow-15-0-sale_order_line_remove :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/sale-workflow&target_branch=13.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&target_branch=15.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -52,7 +52,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -82,6 +82,6 @@ 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/sale-workflow `_ project on GitHub. +This module is part of the `OCA/sale-workflow `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_order_line_remove/__init__.py b/sale_order_line_remove/__init__.py index 0ee8b5073e2..0650744f6bc 100644 --- a/sale_order_line_remove/__init__.py +++ b/sale_order_line_remove/__init__.py @@ -1,2 +1 @@ from . import models -from . import tests diff --git a/sale_order_line_remove/__manifest__.py b/sale_order_line_remove/__manifest__.py index 60d43dcb2f1..3d348e941aa 100644 --- a/sale_order_line_remove/__manifest__.py +++ b/sale_order_line_remove/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { "name": "Sale Order Line Remove", - "version": "13.0.1.0.0", + "version": "15.0.1.0.0", "category": "Sales", "summary": "Allows removal of sale order lines from confirmed " "orders if not invoiced or received", diff --git a/sale_order_line_remove/static/description/index.html b/sale_order_line_remove/static/description/index.html index 72a81b07a7f..7467a885c78 100644 --- a/sale_order_line_remove/static/description/index.html +++ b/sale_order_line_remove/static/description/index.html @@ -367,9 +367,9 @@

Sale Order Line Remove

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:2017e8c089ea3193365d2780d28f22d8fe129ffe9f0796aef565f75343968bdd +!! source digest: sha256:19987b79fe99d4ff465bda1d9b1f07c5570e70b5347127ddb2dcc5849efb6bc4 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

This module allows the removal of sale order lines even after the order has been confirmed, under certain conditions. Specifically, a sale order line can be removed if:

  • It has not been invoiced.
  • @@ -401,7 +401,7 @@

    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.

    +feedback.

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

    @@ -425,7 +425,7 @@

    Maintainers

    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/sale-workflow project on GitHub.

    +

    This module is part of the OCA/sale-workflow project on GitHub.

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

    diff --git a/sale_order_line_remove/tests/test_sale_order_line.py b/sale_order_line_remove/tests/test_sale_order_line.py index beaf0d1fb97..03ecad1439e 100644 --- a/sale_order_line_remove/tests/test_sale_order_line.py +++ b/sale_order_line_remove/tests/test_sale_order_line.py @@ -1,6 +1,7 @@ # Copyright 2023 ForgeFlow, S.L. (https://www.forgeflow.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +from odoo.exceptions import UserError from odoo.tests import TransactionCase @@ -58,7 +59,7 @@ def test_check_line_not_unlinkable(self): for move in picking.move_ids_without_package: move.quantity_done = move.product_uom_qty picking.button_validate() - with self.assertRaises(Exception): + with self.assertRaises(UserError): sale_order_line._check_line_unlink() def test_not_unlinkable_after_picking(self): @@ -78,7 +79,7 @@ def test_not_unlinkable_after_picking(self): for move in picking.move_ids_without_package: move.quantity_done = move.product_uom_qty picking.button_validate() - with self.assertRaises(Exception): + with self.assertRaises(UserError): sale_order_line.unlink() def test_check_line_unlink_delivered(self): @@ -98,7 +99,7 @@ def test_check_line_unlink_delivered(self): for move in picking.move_ids_without_package: move.quantity_done = move.product_uom_qty picking.button_validate() - with self.assertRaises(Exception): + with self.assertRaises(UserError): sale_order_line._check_line_unlink() def test_check_line_unlink_invoiced(self): @@ -119,7 +120,7 @@ def test_check_line_unlink_invoiced(self): move.quantity_done = move.product_uom_qty picking.button_validate() sale_order._create_invoices() - with self.assertRaises(Exception): + with self.assertRaises(UserError): sale_order_line._check_line_unlink() def test_unlink_empty_picking(self): From b9df52da4bacdf02d1138b0c91f6badc4b64e75f Mon Sep 17 00:00:00 2001 From: oca-ci Date: Tue, 14 Nov 2023 11:50:30 +0000 Subject: [PATCH 06/13] [UPD] Update sale_order_line_remove.pot --- sale_order_line_remove/i18n/sale_order_line_remove.pot | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sale_order_line_remove/i18n/sale_order_line_remove.pot b/sale_order_line_remove/i18n/sale_order_line_remove.pot index cb55d497000..12b0de40c2a 100644 --- a/sale_order_line_remove/i18n/sale_order_line_remove.pot +++ b/sale_order_line_remove/i18n/sale_order_line_remove.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 13.0\n" +"Project-Id-Version: Odoo Server 15.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" From 984221c16f3a375584d7ccd978a3dc92fc305057 Mon Sep 17 00:00:00 2001 From: Arnau Date: Tue, 9 Sep 2025 13:45:29 +0200 Subject: [PATCH 07/13] [IMP] sale_order_line_remove: pre-commit auto fixes --- sale_order_line_remove/README.rst | 25 +++++++++++-------- sale_order_line_remove/models/sale_order.py | 4 +-- sale_order_line_remove/pyproject.toml | 3 +++ sale_order_line_remove/readme/CONTRIBUTORS.md | 1 + .../readme/CONTRIBUTORS.rst | 1 - .../{DESCRIPTION.rst => DESCRIPTION.md} | 4 ++- sale_order_line_remove/readme/USAGE.md | 5 ++++ sale_order_line_remove/readme/USAGE.rst | 4 --- .../static/description/index.html | 25 +++++++++++-------- .../tests/test_sale_order_line.py | 2 +- 10 files changed, 44 insertions(+), 30 deletions(-) create mode 100644 sale_order_line_remove/pyproject.toml create mode 100644 sale_order_line_remove/readme/CONTRIBUTORS.md delete mode 100644 sale_order_line_remove/readme/CONTRIBUTORS.rst rename sale_order_line_remove/readme/{DESCRIPTION.rst => DESCRIPTION.md} (53%) create mode 100644 sale_order_line_remove/readme/USAGE.md delete mode 100644 sale_order_line_remove/readme/USAGE.rst diff --git a/sale_order_line_remove/README.rst b/sale_order_line_remove/README.rst index 36dd7656ec6..8a52e1024ca 100644 --- a/sale_order_line_remove/README.rst +++ b/sale_order_line_remove/README.rst @@ -17,18 +17,20 @@ Sale Order Line Remove :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github - :target: https://github.com/OCA/sale-workflow/tree/15.0/sale_order_line_remove + :target: https://github.com/OCA/sale-workflow/tree/18.0/sale_order_line_remove :alt: OCA/sale-workflow .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/sale-workflow-15-0/sale-workflow-15-0-sale_order_line_remove + :target: https://translation.odoo-community.org/projects/sale-workflow-18-0/sale-workflow-18-0-sale_order_line_remove :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/sale-workflow&target_branch=15.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&target_branch=18.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| -This module allows the removal of sale order lines even after the order has been confirmed, under certain conditions. Specifically, a sale order line can be removed if: +This module allows the removal of sale order lines even after the order +has been confirmed, under certain conditions. Specifically, a sale order +line can be removed if: - It has not been invoiced. - It has not been delivered. @@ -44,7 +46,8 @@ Usage Once the module is installed: 1. Go to a sale order. -2. You can now delete a sale order line if it hasn't been invoiced or delivered. +2. You can now delete a sale order line if it hasn't been invoiced or + delivered. Bug Tracker =========== @@ -52,7 +55,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -60,17 +63,17 @@ Credits ======= Authors -~~~~~~~ +------- * ForgeFlow Contributors -~~~~~~~~~~~~ +------------ -* Joan Sisquella +- Joan Sisquella Maintainers -~~~~~~~~~~~ +----------- This module is maintained by the OCA. @@ -82,6 +85,6 @@ 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/sale-workflow `_ project on GitHub. +This module is part of the `OCA/sale-workflow `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_order_line_remove/models/sale_order.py b/sale_order_line_remove/models/sale_order.py index fb64c13f2ef..7f3cc907bb9 100644 --- a/sale_order_line_remove/models/sale_order.py +++ b/sale_order_line_remove/models/sale_order.py @@ -9,7 +9,7 @@ class SaleOrderLine(models.Model): _inherit = "sale.order.line" def _check_line_unlink(self): - non_removable_lines = super(SaleOrderLine, self)._check_line_unlink() + non_removable_lines = super()._check_line_unlink() removable_lines = self.filtered( lambda line: line.state in ("sale", "done") and not line.invoice_lines @@ -43,4 +43,4 @@ def unlink(self): for picking in related_pickings: if not picking.move_ids_without_package: picking.unlink() - return super(SaleOrderLine, self).unlink() + return super().unlink() diff --git a/sale_order_line_remove/pyproject.toml b/sale_order_line_remove/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/sale_order_line_remove/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/sale_order_line_remove/readme/CONTRIBUTORS.md b/sale_order_line_remove/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..2fa75245648 --- /dev/null +++ b/sale_order_line_remove/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Joan Sisquella \ diff --git a/sale_order_line_remove/readme/CONTRIBUTORS.rst b/sale_order_line_remove/readme/CONTRIBUTORS.rst deleted file mode 100644 index 1023a5dd6b1..00000000000 --- a/sale_order_line_remove/readme/CONTRIBUTORS.rst +++ /dev/null @@ -1 +0,0 @@ -* Joan Sisquella diff --git a/sale_order_line_remove/readme/DESCRIPTION.rst b/sale_order_line_remove/readme/DESCRIPTION.md similarity index 53% rename from sale_order_line_remove/readme/DESCRIPTION.rst rename to sale_order_line_remove/readme/DESCRIPTION.md index a780df2764b..593ed1efdc3 100644 --- a/sale_order_line_remove/readme/DESCRIPTION.rst +++ b/sale_order_line_remove/readme/DESCRIPTION.md @@ -1,4 +1,6 @@ -This module allows the removal of sale order lines even after the order has been confirmed, under certain conditions. Specifically, a sale order line can be removed if: +This module allows the removal of sale order lines even after the order +has been confirmed, under certain conditions. Specifically, a sale order +line can be removed if: - It has not been invoiced. - It has not been delivered. diff --git a/sale_order_line_remove/readme/USAGE.md b/sale_order_line_remove/readme/USAGE.md new file mode 100644 index 00000000000..65a6e577552 --- /dev/null +++ b/sale_order_line_remove/readme/USAGE.md @@ -0,0 +1,5 @@ +Once the module is installed: + +1. Go to a sale order. +2. You can now delete a sale order line if it hasn't been invoiced or + delivered. diff --git a/sale_order_line_remove/readme/USAGE.rst b/sale_order_line_remove/readme/USAGE.rst deleted file mode 100644 index 9690625f535..00000000000 --- a/sale_order_line_remove/readme/USAGE.rst +++ /dev/null @@ -1,4 +0,0 @@ -Once the module is installed: - -1. Go to a sale order. -2. You can now delete a sale order line if it hasn't been invoiced or delivered. diff --git a/sale_order_line_remove/static/description/index.html b/sale_order_line_remove/static/description/index.html index 7467a885c78..938a8a60108 100644 --- a/sale_order_line_remove/static/description/index.html +++ b/sale_order_line_remove/static/description/index.html @@ -1,4 +1,3 @@ - @@ -9,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -275,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -301,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { @@ -369,8 +369,10 @@

    Sale Order Line Remove

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:19987b79fe99d4ff465bda1d9b1f07c5570e70b5347127ddb2dcc5849efb6bc4 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

    Beta License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

    -

    This module allows the removal of sale order lines even after the order has been confirmed, under certain conditions. Specifically, a sale order line can be removed if:

    +

    Beta License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

    +

    This module allows the removal of sale order lines even after the order +has been confirmed, under certain conditions. Specifically, a sale order +line can be removed if:

    • It has not been invoiced.
    • It has not been delivered.
    • @@ -393,7 +395,8 @@

      Usage

      Once the module is installed:

      1. Go to a sale order.
      2. -
      3. You can now delete a sale order line if it hasn’t been invoiced or delivered.
      4. +
      5. You can now delete a sale order line if it hasn’t been invoiced or +delivered.
      @@ -401,7 +404,7 @@

      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.

      +feedback.

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

      @@ -421,11 +424,13 @@

      Contributors

      Maintainers

      This module is maintained by the OCA.

      -Odoo Community Association + +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/sale-workflow project on GitHub.

      +

      This module is part of the OCA/sale-workflow project on GitHub.

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

      diff --git a/sale_order_line_remove/tests/test_sale_order_line.py b/sale_order_line_remove/tests/test_sale_order_line.py index 03ecad1439e..dcf621c0fc6 100644 --- a/sale_order_line_remove/tests/test_sale_order_line.py +++ b/sale_order_line_remove/tests/test_sale_order_line.py @@ -7,7 +7,7 @@ class TestSaleOrderLine(TransactionCase): def setUp(self): - super(TestSaleOrderLine, self).setUp() + super().setUp() self.SaleOrder = self.env["sale.order"] self.SaleOrderLine = self.env["sale.order.line"] self.partner = self.env.ref("base.res_partner_2") From 634a347e483d8c1b12e8844280656801f2b5592e Mon Sep 17 00:00:00 2001 From: Arnau Date: Tue, 9 Sep 2025 13:58:16 +0200 Subject: [PATCH 08/13] [MIG] sale_order_line_remove: Migration to 18.0 --- sale_order_line_remove/__manifest__.py | 6 +- sale_order_line_remove/models/__init__.py | 1 + .../models/res_config_settings.py | 14 ++++ sale_order_line_remove/models/sale_order.py | 72 +++++++++++-------- .../tests/test_sale_order_line.py | 22 +++--- .../views/res_config_settings_views.xml | 20 ++++++ 6 files changed, 93 insertions(+), 42 deletions(-) create mode 100644 sale_order_line_remove/models/res_config_settings.py create mode 100644 sale_order_line_remove/views/res_config_settings_views.xml diff --git a/sale_order_line_remove/__manifest__.py b/sale_order_line_remove/__manifest__.py index 3d348e941aa..30466a3cb7b 100644 --- a/sale_order_line_remove/__manifest__.py +++ b/sale_order_line_remove/__manifest__.py @@ -2,15 +2,15 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { "name": "Sale Order Line Remove", - "version": "15.0.1.0.0", + "version": "18.0.1.0.0", "category": "Sales", "summary": "Allows removal of sale order lines from confirmed " "orders if not invoiced or received", "author": "ForgeFlow, Odoo Community Association (OCA)", "website": "https://github.com/OCA/sale-workflow", "license": "AGPL-3", - "depends": ["sale_stock"], - "data": [], + "depends": ["sale_stock", "sale_management"], + "data": ["views/res_config_settings_views.xml"], "installable": True, "application": False, } diff --git a/sale_order_line_remove/models/__init__.py b/sale_order_line_remove/models/__init__.py index 6aacb753131..a556602094c 100644 --- a/sale_order_line_remove/models/__init__.py +++ b/sale_order_line_remove/models/__init__.py @@ -1 +1,2 @@ from . import sale_order +from . import res_config_settings diff --git a/sale_order_line_remove/models/res_config_settings.py b/sale_order_line_remove/models/res_config_settings.py new file mode 100644 index 00000000000..a0e5b101fc3 --- /dev/null +++ b/sale_order_line_remove/models/res_config_settings.py @@ -0,0 +1,14 @@ +# Copyright 2025 ForgeFlow, S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + restrict_sale_order_line_remove = fields.Boolean( + "Allow Sale Order Line Remove", + config_parameter="sale.order.line.remove", + help="Allow removing confirmed sale order lines only " + "if they are not invoiced or delivered.", + ) diff --git a/sale_order_line_remove/models/sale_order.py b/sale_order_line_remove/models/sale_order.py index 7f3cc907bb9..d166e7a6a5d 100644 --- a/sale_order_line_remove/models/sale_order.py +++ b/sale_order_line_remove/models/sale_order.py @@ -10,37 +10,51 @@ class SaleOrderLine(models.Model): def _check_line_unlink(self): non_removable_lines = super()._check_line_unlink() - removable_lines = self.filtered( - lambda line: line.state in ("sale", "done") - and not line.invoice_lines - and not line.move_ids.filtered(lambda move: move.state == "done") - ) - invoiced_lines = self.sudo().filtered( - lambda line: line.state in ("sale", "done") and line.invoice_lines - ) - if invoiced_lines: - raise UserError( - _("You can not remove an order line that has been invoiced") + if ( + not self.env["ir.config_parameter"] + .sudo() + .get_param("sale.order.line.remove") + ): + return non_removable_lines + else: + removable_lines = self.filtered( + lambda line: line.state in ("sale", "done") + and not line.invoice_lines + and not line.move_ids.filtered(lambda move: move.state == "done") ) - delivered_lines = self.sudo().filtered( - lambda line: line.state in ("sale", "done") - and line.move_ids.filtered(lambda move: move.state == "done") - ) - if delivered_lines: - raise UserError( - _("You can not remove an order line that has been delivered") + invoiced_lines = self.sudo().filtered( + lambda line: line.state in ("sale", "done") and line.invoice_lines ) - return non_removable_lines - removable_lines + if invoiced_lines: + raise UserError( + _("You can not remove an order line that has been invoiced") + ) + delivered_lines = self.sudo().filtered( + lambda line: line.state in ("sale", "done") + and line.move_ids.filtered(lambda move: move.state == "done") + ) + if delivered_lines: + raise UserError( + _("You can not remove an order line that has been delivered") + ) + return non_removable_lines - removable_lines def unlink(self): non_removable_lines = self._check_line_unlink() - for line in self - non_removable_lines: - related_pickings = line.move_ids.mapped("picking_id") - line.move_ids.filtered( - lambda move: move.state not in ("done", "cancel") - )._action_cancel() - line.move_ids.filtered(lambda move: move.state != "done").unlink() - for picking in related_pickings: - if not picking.move_ids_without_package: - picking.unlink() - return super().unlink() + if ( + not self.env["ir.config_parameter"] + .sudo() + .get_param("sale.order.line.remove") + ): + return super().unlink() + else: + for line in self - non_removable_lines: + related_pickings = line.move_ids.mapped("picking_id") + line.move_ids.filtered( + lambda move: move.state not in ("done", "cancel") + )._action_cancel() + line.move_ids.filtered(lambda move: move.state != "done").unlink() + for picking in related_pickings: + if not picking.move_ids_without_package: + picking.unlink() + return super().unlink() diff --git a/sale_order_line_remove/tests/test_sale_order_line.py b/sale_order_line_remove/tests/test_sale_order_line.py index dcf621c0fc6..1936822fcff 100644 --- a/sale_order_line_remove/tests/test_sale_order_line.py +++ b/sale_order_line_remove/tests/test_sale_order_line.py @@ -6,13 +6,15 @@ class TestSaleOrderLine(TransactionCase): - def setUp(self): + def setUp(cls): super().setUp() - self.SaleOrder = self.env["sale.order"] - self.SaleOrderLine = self.env["sale.order.line"] - self.partner = self.env.ref("base.res_partner_2") - self.product = self.env.ref("product.product_product_4") - self.uom = self.env.ref("uom.product_uom_unit") + cls.SaleOrder = cls.env["sale.order"] + cls.SaleOrderLine = cls.env["sale.order.line"] + cls.partner = cls.env.ref("base.res_partner_2") + cls.product = cls.env.ref("product.product_product_4") + cls.uom = cls.env.ref("uom.product_uom_unit") + cls.config_param = cls.env["ir.config_parameter"].sudo() + cls.config_param.set_param("sale.order.line.remove", True) def test_check_line_unlink(self): sale_order = self.SaleOrder.create({"partner_id": self.partner.id}) @@ -57,7 +59,7 @@ def test_check_line_not_unlinkable(self): picking.action_confirm() picking.action_assign() for move in picking.move_ids_without_package: - move.quantity_done = move.product_uom_qty + move.quantity = move.product_uom_qty picking.button_validate() with self.assertRaises(UserError): sale_order_line._check_line_unlink() @@ -77,7 +79,7 @@ def test_not_unlinkable_after_picking(self): picking.action_confirm() picking.action_assign() for move in picking.move_ids_without_package: - move.quantity_done = move.product_uom_qty + move.quantity = move.product_uom_qty picking.button_validate() with self.assertRaises(UserError): sale_order_line.unlink() @@ -97,7 +99,7 @@ def test_check_line_unlink_delivered(self): picking.action_confirm() picking.action_assign() for move in picking.move_ids_without_package: - move.quantity_done = move.product_uom_qty + move.quantity = move.product_uom_qty picking.button_validate() with self.assertRaises(UserError): sale_order_line._check_line_unlink() @@ -117,7 +119,7 @@ def test_check_line_unlink_invoiced(self): picking.action_confirm() picking.action_assign() for move in picking.move_ids_without_package: - move.quantity_done = move.product_uom_qty + move.quantity = move.product_uom_qty picking.button_validate() sale_order._create_invoices() with self.assertRaises(UserError): diff --git a/sale_order_line_remove/views/res_config_settings_views.xml b/sale_order_line_remove/views/res_config_settings_views.xml new file mode 100644 index 00000000000..938b6213a17 --- /dev/null +++ b/sale_order_line_remove/views/res_config_settings_views.xml @@ -0,0 +1,20 @@ + + + + res.config.settings.view.form.inherit.sale.order.line.remove + res.config.settings + + + + + + + + + + From 0cf1c1ad35fd8a1d48d4e59cb89094650ce4e402 Mon Sep 17 00:00:00 2001 From: oca-ci Date: Sat, 27 Sep 2025 14:05:41 +0000 Subject: [PATCH 09/13] [UPD] Update sale_order_line_remove.pot --- .../i18n/sale_order_line_remove.pot | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/sale_order_line_remove/i18n/sale_order_line_remove.pot b/sale_order_line_remove/i18n/sale_order_line_remove.pot index 12b0de40c2a..de81f3f4c88 100644 --- a/sale_order_line_remove/i18n/sale_order_line_remove.pot +++ b/sale_order_line_remove/i18n/sale_order_line_remove.pot @@ -4,7 +4,7 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 15.0\n" +"Project-Id-Version: Odoo Server 18.0\n" "Report-Msgid-Bugs-To: \n" "Last-Translator: \n" "Language-Team: \n" @@ -13,19 +13,37 @@ msgstr "" "Content-Transfer-Encoding: \n" "Plural-Forms: \n" +#. module: sale_order_line_remove +#: model:ir.model.fields,field_description:sale_order_line_remove.field_res_config_settings__restrict_sale_order_line_remove +#: model_terms:ir.ui.view,arch_db:sale_order_line_remove.res_config_settings_view_form_sale +msgid "Allow Sale Order Line Remove" +msgstr "" + +#. module: sale_order_line_remove +#: model:ir.model.fields,help:sale_order_line_remove.field_res_config_settings__restrict_sale_order_line_remove +msgid "" +"Allow removing confirmed sale order lines only if they are not invoiced or " +"delivered." +msgstr "" + +#. module: sale_order_line_remove +#: model:ir.model,name:sale_order_line_remove.model_res_config_settings +msgid "Config Settings" +msgstr "" + #. module: sale_order_line_remove #: model:ir.model,name:sale_order_line_remove.model_sale_order_line msgid "Sales Order Line" msgstr "" #. module: sale_order_line_remove +#. odoo-python #: code:addons/sale_order_line_remove/models/sale_order.py:0 -#, python-format msgid "You can not remove an order line that has been delivered" msgstr "" #. module: sale_order_line_remove +#. odoo-python #: code:addons/sale_order_line_remove/models/sale_order.py:0 -#, python-format msgid "You can not remove an order line that has been invoiced" msgstr "" From b69171350ac19705dab358f39869f1540ef5db6a Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Sat, 27 Sep 2025 14:14:12 +0000 Subject: [PATCH 10/13] [BOT] post-merge updates --- sale_order_line_remove/README.rst | 8 ++++-- .../static/description/index.html | 28 +++++++++++-------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/sale_order_line_remove/README.rst b/sale_order_line_remove/README.rst index 8a52e1024ca..68de293dfd0 100644 --- a/sale_order_line_remove/README.rst +++ b/sale_order_line_remove/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ====================== Sale Order Line Remove ====================== @@ -7,13 +11,13 @@ Sale Order Line Remove !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:19987b79fe99d4ff465bda1d9b1f07c5570e70b5347127ddb2dcc5849efb6bc4 + !! source digest: sha256:92c4d50bdbf5dda19487295fa744ed8f013ec29079a78d1ef8eb9bf5d22692d9 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |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 +.. |badge2| image:: https://img.shields.io/badge/license-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%2Fsale--workflow-lightgray.png?logo=github diff --git a/sale_order_line_remove/static/description/index.html b/sale_order_line_remove/static/description/index.html index 938a8a60108..007ba5b96b0 100644 --- a/sale_order_line_remove/static/description/index.html +++ b/sale_order_line_remove/static/description/index.html @@ -3,7 +3,7 @@ -Sale Order Line Remove +README.rst -
      -

      Sale Order Line Remove

      +
      + + +Odoo Community Association + +
      +

      Sale Order Line Remove

      -

      Beta License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

      +

      Beta License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

      This module allows the removal of sale order lines even after the order has been confirmed, under certain conditions. Specifically, a sale order line can be removed if:

      @@ -391,7 +396,7 @@

      Sale Order Line Remove

    -

    Usage

    +

    Usage

    Once the module is installed:

    1. Go to a sale order.
    2. @@ -400,7 +405,7 @@

      Usage

    -

    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 @@ -408,21 +413,21 @@

    Bug Tracker

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

    + From c347ab26fc9112b42916ff043b4527db960bc5e4 Mon Sep 17 00:00:00 2001 From: mymage Date: Sun, 28 Sep 2025 14:01:44 +0000 Subject: [PATCH 11/13] Added translation using Weblate (Italian) --- sale_order_line_remove/i18n/it.po | 50 +++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 sale_order_line_remove/i18n/it.po diff --git a/sale_order_line_remove/i18n/it.po b/sale_order_line_remove/i18n/it.po new file mode 100644 index 00000000000..b077ade8c76 --- /dev/null +++ b/sale_order_line_remove/i18n/it.po @@ -0,0 +1,50 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_line_remove +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" + +#. module: sale_order_line_remove +#: model:ir.model.fields,field_description:sale_order_line_remove.field_res_config_settings__restrict_sale_order_line_remove +#: model_terms:ir.ui.view,arch_db:sale_order_line_remove.res_config_settings_view_form_sale +msgid "Allow Sale Order Line Remove" +msgstr "" + +#. module: sale_order_line_remove +#: model:ir.model.fields,help:sale_order_line_remove.field_res_config_settings__restrict_sale_order_line_remove +msgid "" +"Allow removing confirmed sale order lines only if they are not invoiced or " +"delivered." +msgstr "" + +#. module: sale_order_line_remove +#: model:ir.model,name:sale_order_line_remove.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: sale_order_line_remove +#: model:ir.model,name:sale_order_line_remove.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_order_line_remove +#. odoo-python +#: code:addons/sale_order_line_remove/models/sale_order.py:0 +msgid "You can not remove an order line that has been delivered" +msgstr "" + +#. module: sale_order_line_remove +#. odoo-python +#: code:addons/sale_order_line_remove/models/sale_order.py:0 +msgid "You can not remove an order line that has been invoiced" +msgstr "" From 5abe4db8f7a35256d07ef7ef58040222abd65ec2 Mon Sep 17 00:00:00 2001 From: mymage Date: Mon, 29 Sep 2025 15:08:59 +0000 Subject: [PATCH 12/13] Translated using Weblate (Italian) Currently translated at 100.0% (6 of 6 strings) Translation: sale-workflow-18.0/sale-workflow-18.0-sale_order_line_remove Translate-URL: https://translation.odoo-community.org/projects/sale-workflow-18-0/sale-workflow-18-0-sale_order_line_remove/it/ --- sale_order_line_remove/i18n/it.po | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/sale_order_line_remove/i18n/it.po b/sale_order_line_remove/i18n/it.po index b077ade8c76..fc1850d1d7d 100644 --- a/sale_order_line_remove/i18n/it.po +++ b/sale_order_line_remove/i18n/it.po @@ -6,19 +6,21 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 18.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2025-09-29 17:43+0000\n" +"Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" #. module: sale_order_line_remove #: model:ir.model.fields,field_description:sale_order_line_remove.field_res_config_settings__restrict_sale_order_line_remove #: model_terms:ir.ui.view,arch_db:sale_order_line_remove.res_config_settings_view_form_sale msgid "Allow Sale Order Line Remove" -msgstr "" +msgstr "Consente rimozione riga ordine vendita" #. module: sale_order_line_remove #: model:ir.model.fields,help:sale_order_line_remove.field_res_config_settings__restrict_sale_order_line_remove @@ -26,25 +28,27 @@ msgid "" "Allow removing confirmed sale order lines only if they are not invoiced or " "delivered." msgstr "" +"Consente la rimozione di righe ordine di vendita confermate solo se non sono " +"fatturate o consegnate." #. module: sale_order_line_remove #: model:ir.model,name:sale_order_line_remove.model_res_config_settings msgid "Config Settings" -msgstr "" +msgstr "Impostazioni configurazione" #. module: sale_order_line_remove #: model:ir.model,name:sale_order_line_remove.model_sale_order_line msgid "Sales Order Line" -msgstr "" +msgstr "Riga ordine di vendita" #. module: sale_order_line_remove #. odoo-python #: code:addons/sale_order_line_remove/models/sale_order.py:0 msgid "You can not remove an order line that has been delivered" -msgstr "" +msgstr "Non si può rimuovere una riga ordine che è stata consegnata" #. module: sale_order_line_remove #. odoo-python #: code:addons/sale_order_line_remove/models/sale_order.py:0 msgid "You can not remove an order line that has been invoiced" -msgstr "" +msgstr "NOn si può rimuovere una riga ordine che è stata fatturata" From f487af5d6f2650badaf06f75f4ff96ebf8080238 Mon Sep 17 00:00:00 2001 From: Bhavesh Heliconia Date: Fri, 17 Apr 2026 13:50:34 +0530 Subject: [PATCH 13/13] [MIG] sale_order_line_remove: Migration to 19.0 --- sale_order_line_remove/README.rst | 13 ++++--- sale_order_line_remove/__manifest__.py | 2 +- .../models/res_config_settings.py | 1 + sale_order_line_remove/models/sale_order.py | 12 ++++-- sale_order_line_remove/readme/CONTRIBUTORS.md | 2 + .../static/description/index.html | 10 +++-- .../tests/test_sale_order_line.py | 39 ++++++++++--------- 7 files changed, 48 insertions(+), 31 deletions(-) diff --git a/sale_order_line_remove/README.rst b/sale_order_line_remove/README.rst index 68de293dfd0..3125f4ac67e 100644 --- a/sale_order_line_remove/README.rst +++ b/sale_order_line_remove/README.rst @@ -21,13 +21,13 @@ Sale Order Line Remove :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github - :target: https://github.com/OCA/sale-workflow/tree/18.0/sale_order_line_remove + :target: https://github.com/OCA/sale-workflow/tree/19.0/sale_order_line_remove :alt: OCA/sale-workflow .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/sale-workflow-18-0/sale-workflow-18-0-sale_order_line_remove + :target: https://translation.odoo-community.org/projects/sale-workflow-19-0/sale-workflow-19-0-sale_order_line_remove :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/sale-workflow&target_branch=18.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&target_branch=19.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -59,7 +59,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -75,6 +75,9 @@ Contributors ------------ - Joan Sisquella +- `Heliconia Solutions Pvt. Ltd. `__ + + - Bhavesh Heliconia Maintainers ----------- @@ -89,6 +92,6 @@ 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/sale-workflow `_ project on GitHub. +This module is part of the `OCA/sale-workflow `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_order_line_remove/__manifest__.py b/sale_order_line_remove/__manifest__.py index 30466a3cb7b..1565663f145 100644 --- a/sale_order_line_remove/__manifest__.py +++ b/sale_order_line_remove/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). { "name": "Sale Order Line Remove", - "version": "18.0.1.0.0", + "version": "19.0.1.0.0", "category": "Sales", "summary": "Allows removal of sale order lines from confirmed " "orders if not invoiced or received", diff --git a/sale_order_line_remove/models/res_config_settings.py b/sale_order_line_remove/models/res_config_settings.py index a0e5b101fc3..935dd5c583a 100644 --- a/sale_order_line_remove/models/res_config_settings.py +++ b/sale_order_line_remove/models/res_config_settings.py @@ -6,6 +6,7 @@ class ResConfigSettings(models.TransientModel): _inherit = "res.config.settings" + restrict_sale_order_line_remove = fields.Boolean( "Allow Sale Order Line Remove", config_parameter="sale.order.line.remove", diff --git a/sale_order_line_remove/models/sale_order.py b/sale_order_line_remove/models/sale_order.py index d166e7a6a5d..6c1808e0465 100644 --- a/sale_order_line_remove/models/sale_order.py +++ b/sale_order_line_remove/models/sale_order.py @@ -1,7 +1,7 @@ # Copyright 2023 ForgeFlow, S.L. (https://www.forgeflow.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -from odoo import _, models +from odoo import models from odoo.exceptions import UserError @@ -27,7 +27,9 @@ def _check_line_unlink(self): ) if invoiced_lines: raise UserError( - _("You can not remove an order line that has been invoiced") + self.env._( + "You can not remove an order line that has been invoiced" + ) ) delivered_lines = self.sudo().filtered( lambda line: line.state in ("sale", "done") @@ -35,7 +37,9 @@ def _check_line_unlink(self): ) if delivered_lines: raise UserError( - _("You can not remove an order line that has been delivered") + self.env._( + "You can not remove an order line that has been delivered" + ) ) return non_removable_lines - removable_lines @@ -55,6 +59,6 @@ def unlink(self): )._action_cancel() line.move_ids.filtered(lambda move: move.state != "done").unlink() for picking in related_pickings: - if not picking.move_ids_without_package: + if not picking.move_ids: picking.unlink() return super().unlink() diff --git a/sale_order_line_remove/readme/CONTRIBUTORS.md b/sale_order_line_remove/readme/CONTRIBUTORS.md index 2fa75245648..28afb87e378 100644 --- a/sale_order_line_remove/readme/CONTRIBUTORS.md +++ b/sale_order_line_remove/readme/CONTRIBUTORS.md @@ -1 +1,3 @@ - Joan Sisquella \ +- [Heliconia Solutions Pvt. Ltd.](https://www.heliconia.io) + - Bhavesh Heliconia diff --git a/sale_order_line_remove/static/description/index.html b/sale_order_line_remove/static/description/index.html index 007ba5b96b0..029ed4a9f96 100644 --- a/sale_order_line_remove/static/description/index.html +++ b/sale_order_line_remove/static/description/index.html @@ -374,7 +374,7 @@

    Sale Order Line Remove

    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:92c4d50bdbf5dda19487295fa744ed8f013ec29079a78d1ef8eb9bf5d22692d9 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

    Beta License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

    +

    Beta License: AGPL-3 OCA/sale-workflow Translate me on Weblate Try me on Runboat

    This module allows the removal of sale order lines even after the order has been confirmed, under certain conditions. Specifically, a sale order line can be removed if:

    @@ -409,7 +409,7 @@

    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.

    +feedback.

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

    @@ -424,6 +424,10 @@

    Authors

    Contributors

    @@ -435,7 +439,7 @@

    Maintainers

    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/sale-workflow project on GitHub.

    +

    This module is part of the OCA/sale-workflow project on GitHub.

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

    diff --git a/sale_order_line_remove/tests/test_sale_order_line.py b/sale_order_line_remove/tests/test_sale_order_line.py index 1936822fcff..d5ff36cef09 100644 --- a/sale_order_line_remove/tests/test_sale_order_line.py +++ b/sale_order_line_remove/tests/test_sale_order_line.py @@ -2,16 +2,19 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from odoo.exceptions import UserError -from odoo.tests import TransactionCase +from odoo.addons.base.tests.common import BaseCommon -class TestSaleOrderLine(TransactionCase): - def setUp(cls): - super().setUp() + +class TestSaleOrderLine(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() cls.SaleOrder = cls.env["sale.order"] cls.SaleOrderLine = cls.env["sale.order.line"] - cls.partner = cls.env.ref("base.res_partner_2") - cls.product = cls.env.ref("product.product_product_4") + cls.product = cls.env["product.product"].create( + {"name": "Test Product", "type": "consu"} + ) cls.uom = cls.env.ref("uom.product_uom_unit") cls.config_param = cls.env["ir.config_parameter"].sudo() cls.config_param.set_param("sale.order.line.remove", True) @@ -24,7 +27,7 @@ def test_check_line_unlink(self): "order_id": sale_order.id, "product_id": self.product.id, "product_uom_qty": 1, - "product_uom": self.uom.id, + "product_uom_id": self.uom.id, } ) non_removable_lines = sale_order_line._check_line_unlink() @@ -38,7 +41,7 @@ def test_unlink(self): "order_id": sale_order.id, "product_id": self.product.id, "product_uom_qty": 1, - "product_uom": self.uom.id, + "product_uom_id": self.uom.id, } ) sale_order_line.unlink() @@ -52,13 +55,13 @@ def test_check_line_not_unlinkable(self): "order_id": sale_order.id, "product_id": self.product.id, "product_uom_qty": 1, - "product_uom": self.uom.id, + "product_uom_id": self.uom.id, } ) picking = sale_order.picking_ids[0] picking.action_confirm() picking.action_assign() - for move in picking.move_ids_without_package: + for move in picking.move_ids: move.quantity = move.product_uom_qty picking.button_validate() with self.assertRaises(UserError): @@ -72,13 +75,13 @@ def test_not_unlinkable_after_picking(self): "order_id": sale_order.id, "product_id": self.product.id, "product_uom_qty": 1, - "product_uom": self.uom.id, + "product_uom_id": self.uom.id, } ) picking = sale_order.picking_ids[0] picking.action_confirm() picking.action_assign() - for move in picking.move_ids_without_package: + for move in picking.move_ids: move.quantity = move.product_uom_qty picking.button_validate() with self.assertRaises(UserError): @@ -92,13 +95,13 @@ def test_check_line_unlink_delivered(self): "order_id": sale_order.id, "product_id": self.product.id, "product_uom_qty": 1, - "product_uom": self.uom.id, + "product_uom_id": self.uom.id, } ) picking = sale_order.picking_ids[0] picking.action_confirm() picking.action_assign() - for move in picking.move_ids_without_package: + for move in picking.move_ids: move.quantity = move.product_uom_qty picking.button_validate() with self.assertRaises(UserError): @@ -112,13 +115,13 @@ def test_check_line_unlink_invoiced(self): "order_id": sale_order.id, "product_id": self.product.id, "product_uom_qty": 1, - "product_uom": self.uom.id, + "product_uom_id": self.uom.id, } ) picking = sale_order.picking_ids[0] picking.action_confirm() picking.action_assign() - for move in picking.move_ids_without_package: + for move in picking.move_ids: move.quantity = move.product_uom_qty picking.button_validate() sale_order._create_invoices() @@ -133,7 +136,7 @@ def test_unlink_empty_picking(self): "order_id": sale_order.id, "product_id": self.product.id, "product_uom_qty": 1, - "product_uom": self.uom.id, + "product_uom_id": self.uom.id, } ) sale_order_line2 = self.SaleOrderLine.create( @@ -141,7 +144,7 @@ def test_unlink_empty_picking(self): "order_id": sale_order.id, "product_id": self.product.id, "product_uom_qty": 1, - "product_uom": self.uom.id, + "product_uom_id": self.uom.id, } ) picking = sale_order.picking_ids[0]