diff --git a/sale_order_line_remove/README.rst b/sale_order_line_remove/README.rst new file mode 100644 index 00000000000..3125f4ac67e --- /dev/null +++ b/sale_order_line_remove/README.rst @@ -0,0 +1,97 @@ +.. 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 +====================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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/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 + :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-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=19.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 +- `Heliconia Solutions Pvt. Ltd. `__ + + - Bhavesh Heliconia + +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/__init__.py b/sale_order_line_remove/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/sale_order_line_remove/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/sale_order_line_remove/__manifest__.py b/sale_order_line_remove/__manifest__.py new file mode 100644 index 00000000000..1565663f145 --- /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": "19.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", "sale_management"], + "data": ["views/res_config_settings_views.xml"], + "installable": True, + "application": False, +} diff --git a/sale_order_line_remove/i18n/it.po b/sale_order_line_remove/i18n/it.po new file mode 100644 index 00000000000..fc1850d1d7d --- /dev/null +++ b/sale_order_line_remove/i18n/it.po @@ -0,0 +1,54 @@ +# 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" +"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 "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 +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 "Impostazioni configurazione" + +#. module: sale_order_line_remove +#: model:ir.model,name:sale_order_line_remove.model_sale_order_line +msgid "Sales Order Line" +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 "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 "NOn si può rimuovere una riga ordine che è stata fatturata" 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..de81f3f4c88 --- /dev/null +++ b/sale_order_line_remove/i18n/sale_order_line_remove.pot @@ -0,0 +1,49 @@ +# 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: \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.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 "" diff --git a/sale_order_line_remove/models/__init__.py b/sale_order_line_remove/models/__init__.py new file mode 100644 index 00000000000..a556602094c --- /dev/null +++ b/sale_order_line_remove/models/__init__.py @@ -0,0 +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..935dd5c583a --- /dev/null +++ b/sale_order_line_remove/models/res_config_settings.py @@ -0,0 +1,15 @@ +# 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 new file mode 100644 index 00000000000..6c1808e0465 --- /dev/null +++ b/sale_order_line_remove/models/sale_order.py @@ -0,0 +1,64 @@ +# 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()._check_line_unlink() + 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") + ) + invoiced_lines = self.sudo().filtered( + lambda line: line.state in ("sale", "done") and line.invoice_lines + ) + if invoiced_lines: + raise UserError( + 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") + and line.move_ids.filtered(lambda move: move.state == "done") + ) + if delivered_lines: + raise UserError( + self.env._( + "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() + 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: + picking.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..28afb87e378 --- /dev/null +++ b/sale_order_line_remove/readme/CONTRIBUTORS.md @@ -0,0 +1,3 @@ +- Joan Sisquella \ +- [Heliconia Solutions Pvt. Ltd.](https://www.heliconia.io) + - Bhavesh Heliconia diff --git a/sale_order_line_remove/readme/DESCRIPTION.md b/sale_order_line_remove/readme/DESCRIPTION.md new file mode 100644 index 00000000000..593ed1efdc3 --- /dev/null +++ b/sale_order_line_remove/readme/DESCRIPTION.md @@ -0,0 +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: + +- 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/static/description/icon.png b/sale_order_line_remove/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/sale_order_line_remove/static/description/icon.png differ 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..029ed4a9f96 --- /dev/null +++ b/sale_order_line_remove/static/description/index.html @@ -0,0 +1,449 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

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.

+
+
+
+
+ + 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..d5ff36cef09 --- /dev/null +++ b/sale_order_line_remove/tests/test_sale_order_line.py @@ -0,0 +1,159 @@ +# 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.addons.base.tests.common import BaseCommon + + +class TestSaleOrderLine(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.SaleOrder = cls.env["sale.order"] + cls.SaleOrderLine = cls.env["sale.order.line"] + 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) + + 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_id": 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_id": 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_id": self.uom.id, + } + ) + picking = sale_order.picking_ids[0] + picking.action_confirm() + picking.action_assign() + for move in picking.move_ids: + move.quantity = move.product_uom_qty + picking.button_validate() + with self.assertRaises(UserError): + 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_id": self.uom.id, + } + ) + picking = sale_order.picking_ids[0] + picking.action_confirm() + picking.action_assign() + for move in picking.move_ids: + move.quantity = move.product_uom_qty + picking.button_validate() + with self.assertRaises(UserError): + 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_id": self.uom.id, + } + ) + picking = sale_order.picking_ids[0] + picking.action_confirm() + picking.action_assign() + for move in picking.move_ids: + move.quantity = move.product_uom_qty + picking.button_validate() + with self.assertRaises(UserError): + 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_id": self.uom.id, + } + ) + picking = sale_order.picking_ids[0] + picking.action_confirm() + picking.action_assign() + for move in picking.move_ids: + move.quantity = move.product_uom_qty + picking.button_validate() + sale_order._create_invoices() + with self.assertRaises(UserError): + 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_id": 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_id": 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") 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 + + + + + + + + + + diff --git a/sale_order_line_stock_move_history/README.rst b/sale_order_line_stock_move_history/README.rst new file mode 100644 index 00000000000..9870004f5e6 --- /dev/null +++ b/sale_order_line_stock_move_history/README.rst @@ -0,0 +1,102 @@ +.. 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 Stock Moves History +=================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:d31385b62827049cf560d8a16ff289dde011517b3eeefd580d9d2c008c3b04f6 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/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 + :target: https://github.com/OCA/sale-workflow/tree/19.0/sale_order_line_stock_move_history + :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-19-0/sale-workflow-19-0-sale_order_line_stock_move_history + :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=19.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module provides a button on each sale order line to view the stock +moves history related to the product of that sale order line. It +enhances the visibility of stock movements directly from the sales order +interface. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +- Navigate to Sales. +- Create or open a sale order. +- On each sale order line, next to the 'Delivered' field, you will find + a button to view the stock moves history for the product in that sale + order. + +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 +------- + +* APSL-Nagarro + +Contributors +------------ + +`APSL-Nagarro `__: + +- Patryk Pyczko + +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. + +.. |maintainer-ppyczko| image:: https://github.com/ppyczko.png?size=40px + :target: https://github.com/ppyczko + :alt: ppyczko + +Current `maintainer `__: + +|maintainer-ppyczko| + +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_stock_move_history/__init__.py b/sale_order_line_stock_move_history/__init__.py new file mode 100644 index 00000000000..0b8460dfec6 --- /dev/null +++ b/sale_order_line_stock_move_history/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Patryk Pyczko (APSL-Nagarro) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import models diff --git a/sale_order_line_stock_move_history/__manifest__.py b/sale_order_line_stock_move_history/__manifest__.py new file mode 100644 index 00000000000..88984cb8d3f --- /dev/null +++ b/sale_order_line_stock_move_history/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2025 Patryk Pyczko (APSL-Nagarro) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Sale Order Line Stock Moves History", + "version": "19.0.1.0.0", + "summary": "Show stock moves history for sale order lines", + "website": "https://github.com/OCA/sale-workflow", + "category": "Sales Management", + "author": "APSL-Nagarro, Odoo Community Association (OCA)", + "maintainers": ["ppyczko"], + "license": "AGPL-3", + "installable": True, + "application": False, + "depends": ["sale_management", "sale_stock"], + "data": ["views/sale_order_views.xml", "views/stock_move_views.xml"], +} diff --git a/sale_order_line_stock_move_history/i18n/es.po b/sale_order_line_stock_move_history/i18n/es.po new file mode 100644 index 00000000000..d34f8179a9c --- /dev/null +++ b/sale_order_line_stock_move_history/i18n/es.po @@ -0,0 +1,57 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_line_stock_move_history +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-07-08 09:17+0000\n" +"PO-Revision-Date: 2025-07-08 09:17+0000\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_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Done By" +msgstr "Realizado por" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Quantity" +msgstr "Cantidad" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Reference" +msgstr "Referencia" + +#. module: sale_order_line_stock_move_history +#: model:ir.model,name:sale_order_line_stock_move_history.model_sale_order_line +msgid "Sales Order Line" +msgstr "Línea de pedido de venta" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Stock Move History" +msgstr "Historial de movimientos de stock" + +#. module: sale_order_line_stock_move_history +#. odoo-python +#: code:addons/sale_order_line_stock_move_history/models/sale_order_line.py:0 +msgid "Stock Moves History for %s" +msgstr "Historial de movimientos de stock para %s" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Unit" +msgstr "Unidad" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.view_order_form_inherit_stock_moves +msgid "View Stock Moves History" +msgstr "Ver historial de movimientos de stock" diff --git a/sale_order_line_stock_move_history/i18n/it.po b/sale_order_line_stock_move_history/i18n/it.po new file mode 100644 index 00000000000..bd84f890b12 --- /dev/null +++ b/sale_order_line_stock_move_history/i18n/it.po @@ -0,0 +1,58 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_line_stock_move_history +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-07-23 14:25+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_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Done By" +msgstr "Eseguito da" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Quantity" +msgstr "Quantità" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Reference" +msgstr "Riferimento" + +#. module: sale_order_line_stock_move_history +#: model:ir.model,name:sale_order_line_stock_move_history.model_sale_order_line +msgid "Sales Order Line" +msgstr "Riga ordine di vendita" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Stock Move History" +msgstr "Cronologia movimenti magazzino" + +#. module: sale_order_line_stock_move_history +#. odoo-python +#: code:addons/sale_order_line_stock_move_history/models/sale_order_line.py:0 +msgid "Stock Moves History for %s" +msgstr "Cronologia movimenti magazzino per %s" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Unit" +msgstr "Unità" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.view_order_form_inherit_stock_moves +msgid "View Stock Moves History" +msgstr "Visualizza cronologia movimenti di magazzino" diff --git a/sale_order_line_stock_move_history/i18n/sale_order_line_stock_move_history.pot b/sale_order_line_stock_move_history/i18n/sale_order_line_stock_move_history.pot new file mode 100644 index 00000000000..b0e5e92536a --- /dev/null +++ b/sale_order_line_stock_move_history/i18n/sale_order_line_stock_move_history.pot @@ -0,0 +1,55 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_order_line_stock_move_history +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.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_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Done By" +msgstr "" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Quantity" +msgstr "" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Reference" +msgstr "" + +#. module: sale_order_line_stock_move_history +#: model:ir.model,name:sale_order_line_stock_move_history.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Stock Move History" +msgstr "" + +#. module: sale_order_line_stock_move_history +#. odoo-python +#: code:addons/sale_order_line_stock_move_history/models/sale_order_line.py:0 +msgid "Stock Moves History for %s" +msgstr "" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.stock_move_line_history +msgid "Unit" +msgstr "" + +#. module: sale_order_line_stock_move_history +#: model_terms:ir.ui.view,arch_db:sale_order_line_stock_move_history.view_order_form_inherit_stock_moves +msgid "View Stock Moves History" +msgstr "" diff --git a/sale_order_line_stock_move_history/models/__init__.py b/sale_order_line_stock_move_history/models/__init__.py new file mode 100644 index 00000000000..4a9a1cee709 --- /dev/null +++ b/sale_order_line_stock_move_history/models/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2025 Patryk Pyczko (APSL-Nagarro) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from . import sale_order_line diff --git a/sale_order_line_stock_move_history/models/sale_order_line.py b/sale_order_line_stock_move_history/models/sale_order_line.py new file mode 100644 index 00000000000..559da3948db --- /dev/null +++ b/sale_order_line_stock_move_history/models/sale_order_line.py @@ -0,0 +1,34 @@ +# Copyright 2025 Patryk Pyczko (APSL-Nagarro) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + def action_view_stock_moves(self): + self.ensure_one() + return { + "type": "ir.actions.act_window", + "name": self.env._( + "Stock Moves History for %s", self.product_id.display_name + ), + "res_model": "stock.move.line", + "view_mode": "list", + "views": [ + ( + self.env.ref( + "sale_order_line_stock_move_history.stock_move_line_history" + ).id, + "list", + ), + ], + "domain": [ + ("move_id.sale_line_id", "=", self.id), + ("product_id", "=", self.product_id.id), + ], + "context": { + "default_product_id": self.product_id.id, + }, + } diff --git a/sale_order_line_stock_move_history/pyproject.toml b/sale_order_line_stock_move_history/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/sale_order_line_stock_move_history/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/sale_order_line_stock_move_history/readme/CONTRIBUTORS.md b/sale_order_line_stock_move_history/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..dd22964145b --- /dev/null +++ b/sale_order_line_stock_move_history/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +[APSL-Nagarro](https://www.apsl.tech): + - Patryk Pyczko \<\> diff --git a/sale_order_line_stock_move_history/readme/DESCRIPTION.md b/sale_order_line_stock_move_history/readme/DESCRIPTION.md new file mode 100644 index 00000000000..4a1fe954899 --- /dev/null +++ b/sale_order_line_stock_move_history/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module provides a button on each sale order line to view the stock moves history related to the product of that sale order line. It enhances the visibility of stock movements directly from the sales order interface. diff --git a/sale_order_line_stock_move_history/readme/USAGE.md b/sale_order_line_stock_move_history/readme/USAGE.md new file mode 100644 index 00000000000..32208541c82 --- /dev/null +++ b/sale_order_line_stock_move_history/readme/USAGE.md @@ -0,0 +1,3 @@ +- Navigate to Sales. +- Create or open a sale order. +- On each sale order line, next to the 'Delivered' field, you will find a button to view the stock moves history for the product in that sale order. diff --git a/sale_order_line_stock_move_history/static/description/icon.png b/sale_order_line_stock_move_history/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/sale_order_line_stock_move_history/static/description/icon.png differ diff --git a/sale_order_line_stock_move_history/static/description/index.html b/sale_order_line_stock_move_history/static/description/index.html new file mode 100644 index 00000000000..d5bddc24614 --- /dev/null +++ b/sale_order_line_stock_move_history/static/description/index.html @@ -0,0 +1,446 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Sale Order Line Stock Moves History

+ +

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

+

This module provides a button on each sale order line to view the stock +moves history related to the product of that sale order line. It +enhances the visibility of stock movements directly from the sales order +interface.

+

Table of contents

+ +
+

Usage

+
    +
  • Navigate to Sales.
  • +
  • Create or open a sale order.
  • +
  • On each sale order line, next to the ‘Delivered’ field, you will find +a button to view the stock moves history for the product in that sale +order.
  • +
+
+
+

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

+
    +
  • APSL-Nagarro
  • +
+
+
+

Contributors

+

APSL-Nagarro:

+ +
+
+

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.

+

Current maintainer:

+

ppyczko

+

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_stock_move_history/views/sale_order_views.xml b/sale_order_line_stock_move_history/views/sale_order_views.xml new file mode 100644 index 00000000000..2a1236dd7aa --- /dev/null +++ b/sale_order_line_stock_move_history/views/sale_order_views.xml @@ -0,0 +1,25 @@ + + + + + sale.order.form.stock.move.button + sale.order + + + +