From bbab526b78cfa53236a9552a6333190312cca186 Mon Sep 17 00:00:00 2001 From: Patryk Pyczko Date: Tue, 14 Jan 2025 15:53:36 +0100 Subject: [PATCH 1/2] [IMP] fieldservice_stock: Compute move_ids from related pickings --- fieldservice_stock/models/fsm_order.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fieldservice_stock/models/fsm_order.py b/fieldservice_stock/models/fsm_order.py index 35d49ce187..717e1ca37d 100644 --- a/fieldservice_stock/models/fsm_order.py +++ b/fieldservice_stock/models/fsm_order.py @@ -54,6 +54,7 @@ def _compute_picking_ids(self): lambda p: p.picking_type_id.code == "incoming" ) order.return_count = len(incoming_pickings.ids) + order.move_ids = order.picking_ids.mapped("move_ids") def action_view_delivery(self): """ From f75f7656f6956cb9d40d473671733d3d6fac29ad Mon Sep 17 00:00:00 2001 From: Patryk Pyczko Date: Mon, 17 Feb 2025 13:23:30 +0100 Subject: [PATCH 2/2] [IMP] fieldservice_stock: Add setting to enable/disable auto-validation of pickings on FSM order completion --- fieldservice_stock/README.rst | 16 ++-- fieldservice_stock/__manifest__.py | 1 + fieldservice_stock/models/__init__.py | 1 + fieldservice_stock/models/fsm_order.py | 30 +++++++ .../models/res_config_settings.py | 15 ++++ fieldservice_stock/readme/CONFIGURE.md | 5 ++ fieldservice_stock/readme/CONTRIBUTORS.md | 2 + .../static/description/index.html | 45 +++++----- fieldservice_stock/tests/__init__.py | 1 + .../tests/test_fsm_order_autovalidate.py | 84 +++++++++++++++++++ .../views/res_config_settings.xml | 22 +++++ 11 files changed, 197 insertions(+), 25 deletions(-) create mode 100644 fieldservice_stock/models/res_config_settings.py create mode 100644 fieldservice_stock/tests/test_fsm_order_autovalidate.py create mode 100644 fieldservice_stock/views/res_config_settings.xml diff --git a/fieldservice_stock/README.rst b/fieldservice_stock/README.rst index eaec5ef634..2b728cd4da 100644 --- a/fieldservice_stock/README.rst +++ b/fieldservice_stock/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ===================== Field Service - Stock ===================== @@ -17,7 +13,7 @@ Field Service - Stock .. |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 +.. |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%2Ffield--service-lightgray.png?logo=github @@ -64,6 +60,13 @@ If you are in a multi-warehouse situation: - Create or select a territory - Set the warehouse that will serve this territory +If you want to enable autovalidation of related pickings when completing +an FSM order: + +- Go to Field Service > Configuration > Settings +- Under the 'Service Orders' tab, check the 'Auto Validate FSM Pickings' + option + Usage ===== @@ -103,6 +106,9 @@ Contributors - Serpent Consulting Services Pvt. Ltd. - Marcel Savegnago - Freni Patel +- `APSL-Nagarro `__: + + - Patryk Pyczko Other credits ------------- diff --git a/fieldservice_stock/__manifest__.py b/fieldservice_stock/__manifest__.py index 2186ead849..085b988e0c 100644 --- a/fieldservice_stock/__manifest__.py +++ b/fieldservice_stock/__manifest__.py @@ -19,6 +19,7 @@ "views/fsm_order.xml", "views/stock.xml", "views/stock_picking.xml", + "views/res_config_settings.xml", ], "pre_init_hook": "_pre_init_hook", "license": "AGPL-3", diff --git a/fieldservice_stock/models/__init__.py b/fieldservice_stock/models/__init__.py index f8f62f5645..f728546081 100644 --- a/fieldservice_stock/models/__init__.py +++ b/fieldservice_stock/models/__init__.py @@ -10,4 +10,5 @@ stock_rule, stock_picking, fsm_wizard, + res_config_settings, ) diff --git a/fieldservice_stock/models/fsm_order.py b/fieldservice_stock/models/fsm_order.py index 717e1ca37d..a81ac1f1c2 100644 --- a/fieldservice_stock/models/fsm_order.py +++ b/fieldservice_stock/models/fsm_order.py @@ -2,6 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, fields, models +from odoo.exceptions import ValidationError class FSMOrder(models.Model): @@ -95,3 +96,32 @@ def action_view_returns(self): action["views"] = [(self.env.ref("stock.view_picking_form").id, "form")] action["res_id"] = return_ids[0] return action + + def action_complete(self): + """Validate related pickings before marking FSM Order as complete.""" + auto_validate = ( + self.env["ir.config_parameter"] + .sudo() + .get_param("fieldservice_stock.auto_validate_pickings", default=False) + ) + + if auto_validate: + for order in self: + for picking in order.picking_ids.filtered( + lambda p: p.state in ["confirmed", "assigned"] + ): + picking.action_assign() + + if any( + move.quantity < move.product_uom_qty + for move in picking.move_ids + ): + raise ValidationError( + f"Not enough stock to complete transfer for FSM Order " + f"{order.name} - {picking.name}. " + f"Please check product quantities." + ) + + picking.button_validate() + + return super().action_complete() diff --git a/fieldservice_stock/models/res_config_settings.py b/fieldservice_stock/models/res_config_settings.py new file mode 100644 index 0000000000..762c8129db --- /dev/null +++ b/fieldservice_stock/models/res_config_settings.py @@ -0,0 +1,15 @@ +# Copyright 2025 Patryk Pyczko (APSL-Nagarro) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + auto_validate_pickings = fields.Boolean( + string="Auto Validate FSM Pickings", + config_parameter="fieldservice_stock.auto_validate_pickings", + help="If enabled, related stock pickings will be automatically " + "validated when an FSM order is completed.", + ) diff --git a/fieldservice_stock/readme/CONFIGURE.md b/fieldservice_stock/readme/CONFIGURE.md index c28dc0bb0c..30220bcd9b 100644 --- a/fieldservice_stock/readme/CONFIGURE.md +++ b/fieldservice_stock/readme/CONFIGURE.md @@ -8,3 +8,8 @@ If you are in a multi-warehouse situation: - Go to Field Service \> Configuration \> Territories - Create or select a territory - Set the warehouse that will serve this territory + +If you want to enable autovalidation of related pickings when completing an FSM order: + +- Go to Field Service > Configuration > Settings +- Under the 'Service Orders' tab, check the 'Auto Validate FSM Pickings' option \ No newline at end of file diff --git a/fieldservice_stock/readme/CONTRIBUTORS.md b/fieldservice_stock/readme/CONTRIBUTORS.md index a2dd37dc9d..c1d60a114e 100644 --- a/fieldservice_stock/readme/CONTRIBUTORS.md +++ b/fieldservice_stock/readme/CONTRIBUTORS.md @@ -3,3 +3,5 @@ - Serpent Consulting Services Pvt. Ltd. \<\> - Marcel Savegnago \<\> - Freni Patel \<\> +- [APSL-Nagarro](https://www.apsl.tech): + - Patryk Pyczko \<\> diff --git a/fieldservice_stock/static/description/index.html b/fieldservice_stock/static/description/index.html index 0bb73e86c8..2ebd219f1b 100644 --- a/fieldservice_stock/static/description/index.html +++ b/fieldservice_stock/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Field Service - Stock -
+
+

Field Service - Stock

- - -Odoo Community Association - -
-

Field Service - Stock

-

Beta License: AGPL-3 OCA/field-service Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/field-service Translate me on Weblate Try me on Runboat

This module is an add-on for the Field Service application in Odoo. It provides a generic framework to allow you to link inventory and stock operations with your field service operations.

@@ -396,14 +391,14 @@

Field Service - Stock

-

Installation

+

Installation

To install Field Service and have the mapping features, you need to install GeoEngine.

Please refer to the installation instructions available at: https://github.com/OCA/geospatial/tree/13.0/base_geoengine

-

Configuration

+

Configuration

To configure this module, you need to:

  • Go to Field Service > Master Data > Locations
  • @@ -415,19 +410,26 @@

    Configuration

  • Create or select a territory
  • Set the warehouse that will serve this territory
+

If you want to enable autovalidation of related pickings when completing +an FSM order:

+
    +
  • Go to Field Service > Configuration > Settings
  • +
  • Under the ‘Service Orders’ tab, check the ‘Auto Validate FSM Pickings’ +option
  • +
-

Usage

+

Usage

This module primarily establishes a connection between stock and field service operations so therefore has no specific usage instructions.

-

Known issues / Roadmap

+

Known issues / Roadmap

The roadmap of the Field Service application is documented on Github.

-

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 @@ -435,33 +437,37 @@

Bug Tracker

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

-

Credits

+

Credits

-

Authors

+

Authors

  • Open Source Integrators
  • Brian McMaster
-

Contributors

+

Contributors

-

Other credits

+

Other credits

The development of this module has been financially supported by:

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -476,6 +482,5 @@

Maintainers

-
diff --git a/fieldservice_stock/tests/__init__.py b/fieldservice_stock/tests/__init__.py index f2e2076220..fa83bbd780 100644 --- a/fieldservice_stock/tests/__init__.py +++ b/fieldservice_stock/tests/__init__.py @@ -3,3 +3,4 @@ from . import test_fsm_stock from . import test_fsm_wizard +from . import test_fsm_order_autovalidate diff --git a/fieldservice_stock/tests/test_fsm_order_autovalidate.py b/fieldservice_stock/tests/test_fsm_order_autovalidate.py new file mode 100644 index 0000000000..5805a866c5 --- /dev/null +++ b/fieldservice_stock/tests/test_fsm_order_autovalidate.py @@ -0,0 +1,84 @@ +from odoo import fields +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase + + +class TestFSMStockActionComplete(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.FSMOrder = cls.env["fsm.order"] + cls.StockPicking = cls.env["stock.picking"] + cls.StockMove = cls.env["stock.move"] + cls.Product = cls.env.ref("stock.product_cable_management_box") + cls.customer_location = cls.env.ref("stock.stock_location_customers") + cls.stock_location = cls.env.ref("stock.stock_location_stock") + cls.picking_type_out = cls.env.ref("stock.picking_type_out") + cls.partner = cls.env["res.partner"].create({"name": "Test Partner"}) + + cls.fsm_order = cls.FSMOrder.create( + { + "location_id": cls.env.ref("fieldservice.test_location").id, + "date_start": fields.Datetime.now(), + "date_end": fields.Datetime.now(), + "request_early": fields.Datetime.now(), + "resolution": "Test resolution", + } + ) + + cls.picking = cls.StockPicking.create( + { + "location_id": cls.stock_location.id, + "location_dest_id": cls.customer_location.id, + "partner_id": cls.partner.id, + "picking_type_id": cls.picking_type_out.id, + } + ) + + cls.stock_move = cls.StockMove.create( + { + "name": "Move Test Product", + "product_id": cls.Product.id, + "product_uom_qty": 5.0, + "product_uom": cls.Product.uom_id.id, + "location_id": cls.stock_location.id, + "location_dest_id": cls.customer_location.id, + "picking_id": cls.picking.id, + } + ) + + cls.picking.action_confirm() + cls.picking.fsm_order_id = cls.fsm_order.id + + def test_action_complete_auto_validate_disabled(self): + """Ensure pickings are not validated when auto_validate_pickings is False.""" + self.env["ir.config_parameter"].sudo().set_param( + "fieldservice_stock.auto_validate_pickings", False + ) + self.stock_move.quantity = self.stock_move.product_uom_qty + self.fsm_order.action_complete() + self.assertNotEqual( + self.picking.state, + "done", + "Picking should not validate when auto-validate is False.", + ) + + def test_action_complete_validates_pickings(self): + """Ensure pickings are validated when auto_validate_pickings is True.""" + self.env["ir.config_parameter"].sudo().set_param( + "fieldservice_stock.auto_validate_pickings", True + ) + self.stock_move.quantity = self.stock_move.product_uom_qty + self.fsm_order.action_complete() + self.assertEqual( + self.picking.state, "done", "Picking should be validated and set to 'done'." + ) + + def test_action_complete_raises_error_on_insufficient_stock(self): + """Ensure ValidationError is raised when stock is insufficient.""" + self.env["ir.config_parameter"].sudo().set_param( + "fieldservice_stock.auto_validate_pickings", True + ) + self.stock_move.product_uom_qty = 9999 + with self.assertRaises(ValidationError): + self.fsm_order.action_complete() diff --git a/fieldservice_stock/views/res_config_settings.xml b/fieldservice_stock/views/res_config_settings.xml new file mode 100644 index 0000000000..dd40dbe84f --- /dev/null +++ b/fieldservice_stock/views/res_config_settings.xml @@ -0,0 +1,22 @@ + + + + + + res.config.settings.view.form.fsm.stock + res.config.settings + + + + + + + + + + +