details:   https://code.tryton.org/tryton/commit/2b4682bac6b5
branch:    default
user:      Cédric Krier <[email protected]>
date:      Wed Aug 19 00:14:52 2026 +0200
description:
        Add scheduled task to close stock period automatically
diffstat:

 modules/stock/CHANGELOG                       |   1 +
 modules/stock/configuration.py                |  17 ++++++++++++++++-
 modules/stock/doc/usage/period.inc.rst        |   7 +++++++
 modules/stock/ir.py                           |   2 ++
 modules/stock/period.py                       |  21 +++++++++++++++++++++
 modules/stock/period.xml                      |   5 +++++
 modules/stock/tests/scenario_stock_period.rst |  10 +++++++---
 modules/stock/view/configuration_form.xml     |   2 ++
 8 files changed, 61 insertions(+), 4 deletions(-)

diffs (159 lines):

diff -r 9539955e9deb -r 2b4682bac6b5 modules/stock/CHANGELOG
--- a/modules/stock/CHANGELOG   Wed Aug 19 00:14:21 2026 +0200
+++ b/modules/stock/CHANGELOG   Wed Aug 19 00:14:52 2026 +0200
@@ -1,3 +1,4 @@
+* Add scheduled task to close period automatically
 * Add scheduled task to create period automatically
 
 Version 8.0.0 - 2026-04-20
diff -r 9539955e9deb -r 2b4682bac6b5 modules/stock/configuration.py
--- a/modules/stock/configuration.py    Wed Aug 19 00:14:21 2026 +0200
+++ b/modules/stock/configuration.py    Wed Aug 19 00:14:52 2026 +0200
@@ -113,6 +113,15 @@
                 ],
             help="Leave it empty to prevent periods "
             "from being created automatically."))
+    period_closing_delay = fields.MultiValue(
+        fields.TimeDelta(
+            "Period Closing Delay",
+            domain=['OR',
+                ('period_closing_delay', '=', None),
+                ('period_closing_delay', '>=', TimeDelta()),
+                ],
+            help="Leave it empty to prevent periods "
+            "from being closed automatically."))
 
     @classmethod
     def multivalue_model(cls, field):
@@ -121,7 +130,7 @@
             return pool.get('stock.configuration.sequence')
         if field == 'shipment_internal_transit':
             return pool.get('stock.configuration.location')
-        if field == 'period_creation_interval':
+        if field in {'period_creation_interval', 'period_closing_delay'}:
             return pool.get('stock.configuration.period')
         return super().multivalue_model(field)
 
@@ -217,3 +226,9 @@
             ('period_creation_interval', '=', None),
             ('period_creation_interval', '>=', TimeDelta(days=1)),
             ])
+    period_closing_delay = fields.TimeDelta(
+        "Period Closing Delay",
+        domain=['OR',
+            ('period_closing_delay', '=', None),
+            ('period_closing_delay', '>=', TimeDelta()),
+            ])
diff -r 9539955e9deb -r 2b4682bac6b5 modules/stock/doc/usage/period.inc.rst
--- a/modules/stock/doc/usage/period.inc.rst    Wed Aug 19 00:14:21 2026 +0200
+++ b/modules/stock/doc/usage/period.inc.rst    Wed Aug 19 00:14:52 2026 +0200
@@ -21,3 +21,10 @@
    configuration <model-stock.configuration>` and add the `company
    <company:model-company.company>` to the `scheduled task
    <trytond:model-ir.cron>` to create periods automatically.
+
+.. tip::
+
+   You can set a :guilabel:`Period Close Delay` on the `stock configuration
+   <model-stock.configuration>` and add the `company
+   <company:model-company.company>` to the `scheduled task
+   <trytond:model-ir.cron>` to close periods automatically after the delay.
diff -r 9539955e9deb -r 2b4682bac6b5 modules/stock/ir.py
--- a/modules/stock/ir.py       Wed Aug 19 00:14:21 2026 +0200
+++ b/modules/stock/ir.py       Wed Aug 19 00:14:52 2026 +0200
@@ -27,11 +27,13 @@
                     "Reschedule Internal Shipments"),
                 ('ir.cron|stock_shipment_assign_try', "Assign Shipments"),
                 ('stock.period|auto_create', "Create Stock Periods"),
+                ('stock.period|auto_close', "Close Stock Periods"),
                 ])
         cls.methods_company_needed.update({
                 'product.product|recompute_cost_price_from_moves',
                 'ir.cron|stock_shipment_assign_try',
                 'stock.period|auto_create',
+                'stock.period|auto_close',
                 })
 
     @classmethod
diff -r 9539955e9deb -r 2b4682bac6b5 modules/stock/period.py
--- a/modules/stock/period.py   Wed Aug 19 00:14:21 2026 +0200
+++ b/modules/stock/period.py   Wed Aug 19 00:14:52 2026 +0200
@@ -202,6 +202,27 @@
                     'company': company,
                     }])[0]
 
+    @classmethod
+    def auto_close(cls):
+        pool = Pool()
+        Date = pool.get('ir.date')
+        Configuration = pool.get('stock.configuration')
+        company = Transaction().context.get('company')
+        if company is None:
+            return
+        config = Configuration(1)
+        delay = config.get_multivalue(
+            'period_closing_delay', company=company)
+        if delay is None:
+            return
+        today = Date.today()
+        periods = cls.search([
+                ('company', '=', company),
+                ('date', '<', today - delay),
+                ('state', '=', 'draft'),
+                ])
+        cls.close(periods)
+
 
 class Cache(ModelSQL, ModelView):
     "It is used to store cached computation of stock quantities"
diff -r 9539955e9deb -r 2b4682bac6b5 modules/stock/period.xml
--- a/modules/stock/period.xml  Wed Aug 19 00:14:21 2026 +0200
+++ b/modules/stock/period.xml  Wed Aug 19 00:14:52 2026 +0200
@@ -123,5 +123,10 @@
             <field name="interval_number" eval="1"/>
             <field name="interval_type">days</field>
         </record>
+        <record model="ir.cron" id="cron_close_period">
+            <field name="method">stock.period|auto_close</field>
+            <field name="interval_number" eval="1"/>
+            <field name="interval_type">days</field>
+        </record>
     </data>
 </tryton>
diff -r 9539955e9deb -r 2b4682bac6b5 
modules/stock/tests/scenario_stock_period.rst
--- a/modules/stock/tests/scenario_stock_period.rst     Wed Aug 19 00:14:21 
2026 +0200
+++ b/modules/stock/tests/scenario_stock_period.rst     Wed Aug 19 00:14:52 
2026 +0200
@@ -49,6 +49,7 @@
 
     >>> configuration = Configuration(1)
     >>> configuration.period_creation_interval = dt.timedelta(days=1)
+    >>> configuration.period_closing_delay = dt.timedelta()
     >>> configuration.save()
 
 Create periods::
@@ -63,9 +64,12 @@
 
 Close the period::
 
-    >>> period.click('close')
-    >>> period.state
-    'closed'
+    >>> cron, = Cron.find([('method', '=', 'stock.period|auto_close')], 
limit=1)
+    >>> cron.companies.append(get_company())
+    >>> cron.click('run_once')
+
+    >>> period, = Period.find([])
+    >>> assertEqual(period.state, 'closed')
 
 Try to create a move::
 
diff -r 9539955e9deb -r 2b4682bac6b5 modules/stock/view/configuration_form.xml
--- a/modules/stock/view/configuration_form.xml Wed Aug 19 00:14:21 2026 +0200
+++ b/modules/stock/view/configuration_form.xml Wed Aug 19 00:14:52 2026 +0200
@@ -21,4 +21,6 @@
     <separator id="period" colspan="4" string="Period"/>
     <label name="period_creation_interval"/>
     <field name="period_creation_interval"/>
+    <label name="period_closing_delay"/>
+    <field name="period_closing_delay"/>
 </form>

Reply via email to