diff --git a/product_state_shortage_queue_job/README.rst b/product_state_shortage_queue_job/README.rst new file mode 100644 index 00000000000..429eda97c4b --- /dev/null +++ b/product_state_shortage_queue_job/README.rst @@ -0,0 +1,99 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +================================ +Product State Shortage Queue Job +================================ + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:9345bf74237dc180bade14715830cc8139dc3740c35e2f937d79017a4b870fc9 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/16.0/product_state_shortage_queue_job + :alt: OCA/product-attribute +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-16-0/product-attribute-16-0-product_state_shortage_queue_job + :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/product-attribute&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module enhances the integration between product state management +and the asynchronous queue job system. + +When product states are automatically reset via the scheduled action +(cron) running as a queue job, this module ensures that detailed +feedback is captured directly on the job record. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Usage +----- + +1. Configure the cron + ``Product: Reset Shortage States based on Available Stock`` to run as + a **Queue Job**. +2. When the job executes, navigate to the jobs list. +3. Open the finished job to see the chatter history, which will contain + the summary of all products processed and updated during that + execution. + +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 +------- + +* ACSONE SA/NV + +Contributors +------------ + +- Nicolas Delbovier nicolas.delbovier@acsone.eu (https://www.acsone.eu/) + +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/product-attribute `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_state_shortage_queue_job/__init__.py b/product_state_shortage_queue_job/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/product_state_shortage_queue_job/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_state_shortage_queue_job/__manifest__.py b/product_state_shortage_queue_job/__manifest__.py new file mode 100644 index 00000000000..a38717c4753 --- /dev/null +++ b/product_state_shortage_queue_job/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2026 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Product State Shortage Queue Job", + "summary": """Adds a summary log on the queue job record that + performed the shortage state reset""", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "ACSONE SA/NV,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/product-attribute", + "depends": ["product_state_shortage", "queue_job_cron"], + "data": [], + "demo": [], +} diff --git a/product_state_shortage_queue_job/models/__init__.py b/product_state_shortage_queue_job/models/__init__.py new file mode 100644 index 00000000000..e8fa8f6bf1e --- /dev/null +++ b/product_state_shortage_queue_job/models/__init__.py @@ -0,0 +1 @@ +from . import product_template diff --git a/product_state_shortage_queue_job/models/product_template.py b/product_state_shortage_queue_job/models/product_template.py new file mode 100644 index 00000000000..55fa7e6f385 --- /dev/null +++ b/product_state_shortage_queue_job/models/product_template.py @@ -0,0 +1,59 @@ +# Copyright 2026 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from itertools import groupby + +from odoo import _, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + def _before_reset_default_state_hook(self): + res = super()._before_reset_default_state_hook() + + cron = self.env.ref( + "product_state_shortage.ir_cron_reset_product_shortage_state" + ) + if not cron or not cron.run_as_queue_job: + return res + + # This search seems a bit sub-optimal since the Job record is already + # somewhere inside the stack but the context here does not contain the + # Job's uuid because it got overridden + current_job = ( + self.env["queue.job"] + .sudo() + .search( + [ + ("model_name", "=", "ir.cron"), + ("state", "=", "started"), + ("name", "=", cron.name), + ], + limit=1, + order="date_started desc", + ) + ) + if not current_job: + return res + + templates_by_state = {} + for state, tmpl_group in groupby(self, key=lambda t: t.product_state_id): + templates_by_state[state] = list(tmpl_group) + + for state, templates in templates_by_state.items(): + product_list_html = "".join( + [f"
  • {t._get_html_link()} (ID: {t.id})
  • " for t in templates] + ) + + message = _( + "

    The following products were in state %(current_state)s " + "and have been reset to default state %(default_state)s:

    " + "
      %(product_list)s
    ", + current_state=state.display_name or _("N/A"), + default_state=self._get_default_product_state().display_name, + product_list=product_list_html, + ) + current_job.message_post(body=message) + + return res diff --git a/product_state_shortage_queue_job/readme/CONTRIBUTORS.md b/product_state_shortage_queue_job/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..e0604c970f9 --- /dev/null +++ b/product_state_shortage_queue_job/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Nicolas Delbovier (https://www.acsone.eu/) \ No newline at end of file diff --git a/product_state_shortage_queue_job/readme/DESCRIPTION.md b/product_state_shortage_queue_job/readme/DESCRIPTION.md new file mode 100644 index 00000000000..0805391a796 --- /dev/null +++ b/product_state_shortage_queue_job/readme/DESCRIPTION.md @@ -0,0 +1,6 @@ +This module enhances the integration between product state management and the +asynchronous queue job system. + +When product states are automatically reset via the scheduled action (cron) +running as a queue job, this module ensures that detailed feedback is +captured directly on the job record. \ No newline at end of file diff --git a/product_state_shortage_queue_job/readme/USAGE.md b/product_state_shortage_queue_job/readme/USAGE.md new file mode 100644 index 00000000000..74ffaa0443e --- /dev/null +++ b/product_state_shortage_queue_job/readme/USAGE.md @@ -0,0 +1,6 @@ +## Usage + +1. Configure the cron `Product: Reset Shortage States based on Available Stock` to run as a **Queue Job**. +2. When the job executes, navigate to the jobs list. +3. Open the finished job to see the chatter history, which will contain + the summary of all products processed and updated during that execution. \ No newline at end of file diff --git a/product_state_shortage_queue_job/static/description/icon.png b/product_state_shortage_queue_job/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_state_shortage_queue_job/static/description/icon.png differ diff --git a/product_state_shortage_queue_job/static/description/index.html b/product_state_shortage_queue_job/static/description/index.html new file mode 100644 index 00000000000..4f3d766699c --- /dev/null +++ b/product_state_shortage_queue_job/static/description/index.html @@ -0,0 +1,452 @@ + + + + + +README.rst + + + +
    + + + +Odoo Community Association + +
    +

    Product State Shortage Queue Job

    + +

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

    +

    This module enhances the integration between product state management +and the asynchronous queue job system.

    +

    When product states are automatically reset via the scheduled action +(cron) running as a queue job, this module ensures that detailed +feedback is captured directly on the job record.

    +

    Table of contents

    + +
    +

    Usage

    +
    +

    Usage

    +
      +
    1. Configure the cron +Product: Reset Shortage States based on Available Stock to run as +a Queue Job.
    2. +
    3. When the job executes, navigate to the jobs list.
    4. +
    5. Open the finished job to see the chatter history, which will contain +the summary of all products processed and updated during that +execution.
    6. +
    +
    +
    +
    +

    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

    +
      +
    • ACSONE SA/NV
    • +
    +
    + +
    +

    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/product-attribute project on GitHub.

    +

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

    +
    +
    +
    +
    + + diff --git a/product_state_shortage_queue_job/tests/__init__.py b/product_state_shortage_queue_job/tests/__init__.py new file mode 100644 index 00000000000..08b5f701dc2 --- /dev/null +++ b/product_state_shortage_queue_job/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_state_shortage_queue_job diff --git a/product_state_shortage_queue_job/tests/test_product_state_shortage_queue_job.py b/product_state_shortage_queue_job/tests/test_product_state_shortage_queue_job.py new file mode 100644 index 00000000000..5fe9d415e55 --- /dev/null +++ b/product_state_shortage_queue_job/tests/test_product_state_shortage_queue_job.py @@ -0,0 +1,68 @@ +# Copyright 2026 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + +from odoo.addons.queue_job.tests.common import JobMixin + + +class TestProductStateShortageQueueJob(TransactionCase, JobMixin): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.reset_state_cron = cls.env.ref( + "product_state_shortage.ir_cron_reset_product_shortage_state" + ) + cls.reset_state_cron.run_as_queue_job = True + + cls.shortage_state_1 = cls.env["product.state"].create( + { + "name": "Shortage 1", + "code": "S1", + "is_shortage": True, + } + ) + cls.shortage_state_2 = cls.env["product.state"].create( + { + "name": "Shortage 2", + "code": "S2", + "is_shortage": True, + } + ) + cls.default_state = cls.env["product.template"]._get_default_product_state() + cls.product_1 = cls.env["product.product"].create( + { + "name": "Test Product", + "product_state_id": cls.shortage_state_1.id, + "detailed_type": "product", + } + ) + cls.product_2 = cls.env["product.product"].create( + { + "name": "Test Product", + "product_state_id": cls.shortage_state_2.id, + "detailed_type": "product", + } + ) + cls.wh = cls.env["stock.warehouse"].search([], limit=1) + cls.loc_shelf_1 = cls.env["stock.location"].create( + {"name": "Shelf 1", "location_id": cls.wh.lot_stock_id.id} + ) + + def test_log_after_reset_state_cron(self): + counter = self.job_counter() + + self.reset_state_cron.method_direct_trigger() + + new_jobs = counter.search_created() + self.assertEqual(len(new_jobs), 1) + + new_jobs.write({"state": "started"}) + + ( + self.product_1 | self.product_2 + ).product_tmpl_id._before_reset_default_state_hook() + + messages = new_jobs.mapped("message_ids.body") + self.assertTrue(any(self.product_1.name in msg for msg in messages)) + self.assertTrue(any(self.product_2.name in msg for msg in messages)) diff --git a/setup/product_state_shortage_queue_job/odoo/addons/product_state_shortage_queue_job b/setup/product_state_shortage_queue_job/odoo/addons/product_state_shortage_queue_job new file mode 120000 index 00000000000..df7eeec7340 --- /dev/null +++ b/setup/product_state_shortage_queue_job/odoo/addons/product_state_shortage_queue_job @@ -0,0 +1 @@ +../../../../product_state_shortage_queue_job \ No newline at end of file diff --git a/setup/product_state_shortage_queue_job/setup.py b/setup/product_state_shortage_queue_job/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/product_state_shortage_queue_job/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/test-requirements.txt b/test-requirements.txt index 66bc2cbae3f..67a48c8762d 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1 +1,2 @@ odoo_test_helper +odoo-addon-product-state-shortage @ git+https://github.com/OCA/product-attribute.git@refs/pull/2276/head#subdirectory=setup/product_state_shortage