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>